mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-24 07:46:48 +00:00
kernel: remove linux 4.0 support
Signed-off-by: Felix Fietkau <nbd@openwrt.org> SVN-Revision: 47412
This commit is contained in:
parent
86a46a817b
commit
ad133b57a9
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
@@ -625,6 +625,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();
|
||||
@@ -632,6 +633,9 @@ int __init init_rootfs(void)
|
||||
} else {
|
||||
err = init_ramfs_fs();
|
||||
}
|
||||
+#else
|
||||
+ err = init_ramfs_fs();
|
||||
+#endif
|
||||
|
||||
if (err)
|
||||
unregister_filesystem(&rootfs_fs_type);
|
@ -1,30 +0,0 @@
|
||||
--- a/drivers/ssb/driver_pcicore.c
|
||||
+++ b/drivers/ssb/driver_pcicore.c
|
||||
@@ -357,6 +357,16 @@ static void ssb_pcicore_init_hostmode(st
|
||||
pcicore_write32(pc, SSB_PCICORE_SBTOPCI2,
|
||||
SSB_PCICORE_SBTOPCI_MEM | SSB_PCI_DMA);
|
||||
|
||||
+ /*
|
||||
+ * Accessing PCI config without a proper delay after devices reset (not
|
||||
+ * GPIO reset) was causing reboots on WRT300N v1.0 (BCM4704).
|
||||
+ * Tested delay 850 us lowered reboot chance to 50-80%, 1000 us fixed it
|
||||
+ * completely. Flushing all writes was also tested but with no luck.
|
||||
+ * The same problem was reported for WRT350N v1 (BCM4705), so we just
|
||||
+ * sleep here unconditionally.
|
||||
+ */
|
||||
+ usleep_range(1000, 2000);
|
||||
+
|
||||
/* Enable PCI bridge BAR0 prefetch and burst */
|
||||
val = PCI_COMMAND_MASTER | PCI_COMMAND_MEMORY;
|
||||
ssb_extpci_write_config(pc, 0, 0, 0, PCI_COMMAND, &val, 2);
|
||||
--- a/drivers/ssb/main.c
|
||||
+++ b/drivers/ssb/main.c
|
||||
@@ -1135,6 +1135,8 @@ static u32 ssb_tmslow_reject_bitmask(str
|
||||
case SSB_IDLOW_SSBREV_25: /* TODO - find the proper REJECT bit */
|
||||
case SSB_IDLOW_SSBREV_27: /* same here */
|
||||
return SSB_TMSLOW_REJECT; /* this is a guess */
|
||||
+ case SSB_IDLOW_SSBREV:
|
||||
+ break;
|
||||
default:
|
||||
WARN(1, KERN_INFO "ssb: Backplane Revision 0x%.8X\n", rev);
|
||||
}
|
@ -1,680 +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);
|
||||
@@ -42,6 +43,9 @@ int bcma_bus_scan(struct bcma_bus *bus);
|
||||
int bcma_sprom_get(struct bcma_bus *bus);
|
||||
|
||||
/* driver_chipcommon.c */
|
||||
+void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
||||
+void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
||||
+void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
||||
#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||
extern struct platform_device bcma_pflash_dev;
|
||||
@@ -52,6 +56,8 @@ int bcma_core_chipcommon_b_init(struct b
|
||||
void bcma_core_chipcommon_b_free(struct bcma_drv_cc_b *ccb);
|
||||
|
||||
/* driver_chipcommon_pmu.c */
|
||||
+void bcma_pmu_early_init(struct bcma_drv_cc *cc);
|
||||
+void bcma_pmu_init(struct bcma_drv_cc *cc);
|
||||
u32 bcma_pmu_get_alp_clock(struct bcma_drv_cc *cc);
|
||||
u32 bcma_pmu_get_cpu_clock(struct bcma_drv_cc *cc);
|
||||
|
||||
@@ -100,7 +106,35 @@ static inline void __exit bcma_host_soc_
|
||||
#endif /* CONFIG_BCMA_HOST_SOC && CONFIG_OF */
|
||||
|
||||
/* driver_pci.c */
|
||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
||||
u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address);
|
||||
+void bcma_core_pci_early_init(struct bcma_drv_pci *pc);
|
||||
+void bcma_core_pci_init(struct bcma_drv_pci *pc);
|
||||
+void bcma_core_pci_up(struct bcma_drv_pci *pc);
|
||||
+void bcma_core_pci_down(struct bcma_drv_pci *pc);
|
||||
+#else
|
||||
+static inline void bcma_core_pci_early_init(struct bcma_drv_pci *pc)
|
||||
+{
|
||||
+ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
||||
+}
|
||||
+static inline void bcma_core_pci_init(struct bcma_drv_pci *pc)
|
||||
+{
|
||||
+ /* Initialization is required for PCI hosted bus */
|
||||
+ WARN_ON(pc->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/* driver_pcie2.c */
|
||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
||||
+void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
|
||||
+void bcma_core_pcie2_up(struct bcma_drv_pcie2 *pcie2);
|
||||
+#else
|
||||
+static inline void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2)
|
||||
+{
|
||||
+ /* Initialization is required for PCI hosted bus */
|
||||
+ WARN_ON(pcie2->core->bus->hosttype == BCMA_HOSTTYPE_PCI);
|
||||
+}
|
||||
+#endif
|
||||
|
||||
extern int bcma_chipco_watchdog_register(struct bcma_drv_cc *cc);
|
||||
|
||||
@@ -117,6 +151,39 @@ static inline void bcma_core_pci_hostmod
|
||||
}
|
||||
#endif /* CONFIG_BCMA_DRIVER_PCI_HOSTMODE */
|
||||
|
||||
+/**************************************************
|
||||
+ * driver_mips.c
|
||||
+ **************************************************/
|
||||
+
|
||||
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
+unsigned int bcma_core_mips_irq(struct bcma_device *dev);
|
||||
+void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
|
||||
+void bcma_core_mips_init(struct bcma_drv_mips *mcore);
|
||||
+#else
|
||||
+static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
|
||||
+{
|
||||
+}
|
||||
+static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+/**************************************************
|
||||
+ * driver_gmac_cmn.c
|
||||
+ **************************************************/
|
||||
+
|
||||
+#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
|
||||
+void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
|
||||
+#else
|
||||
+static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
#ifdef CONFIG_BCMA_DRIVER_GPIO
|
||||
/* driver_gpio.c */
|
||||
int bcma_gpio_init(struct bcma_drv_cc *cc);
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
#include "bcma_private.h"
|
||||
|
||||
+#define BCMA_GPIO_MAX_PINS 32
|
||||
+
|
||||
static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
|
||||
{
|
||||
return container_of(chip, struct bcma_drv_cc, gpio);
|
||||
@@ -76,7 +78,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);
|
||||
@@ -204,6 +206,7 @@ static void bcma_gpio_irq_domain_exit(st
|
||||
|
||||
int bcma_gpio_init(struct bcma_drv_cc *cc)
|
||||
{
|
||||
+ struct bcma_bus *bus = cc->core->bus;
|
||||
struct gpio_chip *chip = &cc->gpio;
|
||||
int err;
|
||||
|
||||
@@ -215,14 +218,14 @@ 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)
|
||||
if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
- switch (cc->core->bus->chipinfo.id) {
|
||||
+ switch (bus->chipinfo.id) {
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
chip->ngpio = 32;
|
||||
@@ -231,13 +234,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
chip->ngpio = 16;
|
||||
}
|
||||
|
||||
- /* There is just one SoC in one device and its GPIO addresses should be
|
||||
- * deterministic to address them more easily. The other buses could get
|
||||
- * a random base number. */
|
||||
- if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
- chip->base = 0;
|
||||
- else
|
||||
- chip->base = -1;
|
||||
+ /*
|
||||
+ * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
|
||||
+ * pin numbers. We don't have Device Tree there and we can't really use
|
||||
+ * relative (per chip) numbers.
|
||||
+ * So let's use predictable base for BCM47XX and "random" for all other.
|
||||
+ */
|
||||
+#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
||||
+#else
|
||||
+ chip->base = -1;
|
||||
+#endif
|
||||
|
||||
err = bcma_gpio_irq_domain_init(cc);
|
||||
if (err)
|
||||
--- a/drivers/bcma/driver_pci.c
|
||||
+++ b/drivers/bcma/driver_pci.c
|
||||
@@ -282,39 +282,6 @@ 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,
|
||||
- bool enable)
|
||||
-{
|
||||
- struct pci_dev *pdev;
|
||||
- u32 coremask, tmp;
|
||||
- int err = 0;
|
||||
-
|
||||
- if (!pc || core->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;
|
||||
-
|
||||
- err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
- if (err)
|
||||
- goto out;
|
||||
-
|
||||
- coremask = BIT(core->core_index) << 8;
|
||||
- if (enable)
|
||||
- tmp |= coremask;
|
||||
- else
|
||||
- tmp &= ~coremask;
|
||||
-
|
||||
- err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
||||
-
|
||||
-out:
|
||||
- return err;
|
||||
-}
|
||||
-EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
|
||||
-
|
||||
static void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
|
||||
{
|
||||
u32 w;
|
||||
@@ -328,28 +295,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,65 @@ 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);
|
||||
+
|
||||
+/* See also si_pci_setup */
|
||||
+int bcma_host_pci_irq_ctl(struct bcma_bus *bus, struct bcma_device *core,
|
||||
+ bool enable)
|
||||
+{
|
||||
+ struct pci_dev *pdev;
|
||||
+ u32 coremask, tmp;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ 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 = bus->host_pci;
|
||||
+
|
||||
+ err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
|
||||
+ if (err)
|
||||
+ goto out;
|
||||
+
|
||||
+ coremask = BIT(core->core_index) << 8;
|
||||
+ if (enable)
|
||||
+ tmp |= coremask;
|
||||
+ else
|
||||
+ tmp &= ~coremask;
|
||||
+
|
||||
+ err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
|
||||
+
|
||||
+out:
|
||||
+ return err;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(bcma_host_pci_irq_ctl);
|
||||
--- 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
|
||||
@@ -4819,7 +4819,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
|
||||
@@ -4866,9 +4866,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_host_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
|
||||
@@ -4668,7 +4668,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);
|
||||
@@ -4959,7 +4959,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_host_pci_irq_ctl(wlc_hw->d11core->bus, wlc_hw->d11core,
|
||||
true);
|
||||
|
||||
/*
|
||||
@@ -4969,12 +4969,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);
|
||||
@@ -5171,7 +5171,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,27 @@ static inline struct bcma_device *bcma_f
|
||||
return bcma_find_core_unit(bus, coreid, 0);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_BCMA_HOST_PCI
|
||||
+extern void bcma_host_pci_up(struct bcma_bus *bus);
|
||||
+extern void bcma_host_pci_down(struct bcma_bus *bus);
|
||||
+extern int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
|
||||
+ struct bcma_device *core, bool enable);
|
||||
+#else
|
||||
+static inline void bcma_host_pci_up(struct bcma_bus *bus)
|
||||
+{
|
||||
+}
|
||||
+static inline void bcma_host_pci_down(struct bcma_bus *bus)
|
||||
+{
|
||||
+}
|
||||
+static inline int bcma_host_pci_irq_ctl(struct bcma_bus *bus,
|
||||
+ struct bcma_device *core, bool enable)
|
||||
+{
|
||||
+ if (bus->hosttype == BCMA_HOSTTYPE_PCI)
|
||||
+ return -ENOTSUPP;
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
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
|
||||
@@ -238,13 +238,13 @@ 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);
|
||||
-extern void bcma_core_pci_up(struct bcma_bus *bus);
|
||||
-extern void bcma_core_pci_down(struct bcma_bus *bus);
|
||||
+#ifdef CONFIG_BCMA_DRIVER_PCI
|
||||
extern void bcma_core_pci_power_save(struct bcma_bus *bus, bool up);
|
||||
+#else
|
||||
+static inline void bcma_core_pci_power_save(struct bcma_bus *bus, bool up)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
|
||||
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
|
||||
extern int bcma_core_pci_plat_dev_init(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)
|
||||
@@ -153,6 +155,4 @@ struct bcma_drv_pcie2 {
|
||||
#define pcie2_set32(pcie2, offset, set) bcma_set32((pcie2)->core, offset, set)
|
||||
#define pcie2_mask32(pcie2, offset, mask) bcma_mask32((pcie2)->core, offset, mask)
|
||||
|
||||
-void bcma_core_pcie2_init(struct bcma_drv_pcie2 *pcie2);
|
||||
-
|
||||
#endif /* LINUX_BCMA_DRIVER_PCIE2_H_ */
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -26,6 +26,7 @@ config BCMA_HOST_PCI_POSSIBLE
|
||||
config BCMA_HOST_PCI
|
||||
bool "Support for BCMA on PCI-host bus"
|
||||
depends on BCMA_HOST_PCI_POSSIBLE
|
||||
+ select BCMA_DRIVER_PCI
|
||||
default y
|
||||
|
||||
config BCMA_DRIVER_PCI_HOSTMODE
|
||||
@@ -44,6 +45,22 @@ config BCMA_HOST_SOC
|
||||
|
||||
If unsure, say N
|
||||
|
||||
+config BCMA_DRIVER_PCI
|
||||
+ bool "BCMA Broadcom PCI core driver"
|
||||
+ depends on BCMA && PCI
|
||||
+ default y
|
||||
+ help
|
||||
+ BCMA bus may have many versions of PCIe core. This driver
|
||||
+ supports:
|
||||
+ 1) PCIe core working in clientmode
|
||||
+ 2) PCIe Gen 2 clientmode core
|
||||
+
|
||||
+ In general PCIe (Gen 2) clientmode core is required on PCIe
|
||||
+ hosted buses. It's responsible for initialization and basic
|
||||
+ hardware management.
|
||||
+ This driver is also prerequisite for a hostmode PCIe core
|
||||
+ support.
|
||||
+
|
||||
config BCMA_DRIVER_MIPS
|
||||
bool "BCMA Broadcom MIPS core driver"
|
||||
depends on BCMA && MIPS
|
||||
--- a/drivers/bcma/Makefile
|
||||
+++ b/drivers/bcma/Makefile
|
||||
@@ -3,8 +3,8 @@ bcma-y += driver_chipcommon.o driver
|
||||
bcma-y += driver_chipcommon_b.o
|
||||
bcma-$(CONFIG_BCMA_SFLASH) += driver_chipcommon_sflash.o
|
||||
bcma-$(CONFIG_BCMA_NFLASH) += driver_chipcommon_nflash.o
|
||||
-bcma-y += driver_pci.o
|
||||
-bcma-y += driver_pcie2.o
|
||||
+bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pci.o
|
||||
+bcma-$(CONFIG_BCMA_DRIVER_PCI) += driver_pcie2.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_PCI_HOSTMODE) += driver_pci_host.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_MIPS) += driver_mips.o
|
||||
bcma-$(CONFIG_BCMA_DRIVER_GMAC_CMN) += driver_gmac_cmn.o
|
||||
--- a/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
+++ b/include/linux/bcma/bcma_driver_chipcommon.h
|
||||
@@ -663,14 +663,6 @@ struct bcma_drv_cc_b {
|
||||
#define bcma_cc_maskset32(cc, offset, mask, set) \
|
||||
bcma_cc_write32(cc, offset, (bcma_cc_read32(cc, offset) & (mask)) | (set))
|
||||
|
||||
-extern void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
||||
-extern void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
||||
-
|
||||
-extern void bcma_chipco_suspend(struct bcma_drv_cc *cc);
|
||||
-extern void bcma_chipco_resume(struct bcma_drv_cc *cc);
|
||||
-
|
||||
-void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
||||
-
|
||||
extern u32 bcma_chipco_watchdog_timer_set(struct bcma_drv_cc *cc, u32 ticks);
|
||||
|
||||
extern u32 bcma_chipco_get_alp_clock(struct bcma_drv_cc *cc);
|
||||
@@ -690,9 +682,6 @@ u32 bcma_chipco_gpio_pullup(struct bcma_
|
||||
u32 bcma_chipco_gpio_pulldown(struct bcma_drv_cc *cc, u32 mask, u32 value);
|
||||
|
||||
/* PMU support */
|
||||
-extern void bcma_pmu_init(struct bcma_drv_cc *cc);
|
||||
-extern void bcma_pmu_early_init(struct bcma_drv_cc *cc);
|
||||
-
|
||||
extern void bcma_chipco_pll_write(struct bcma_drv_cc *cc, u32 offset,
|
||||
u32 value);
|
||||
extern void bcma_chipco_pll_maskset(struct bcma_drv_cc *cc, u32 offset,
|
||||
--- a/include/linux/bcma/bcma_driver_gmac_cmn.h
|
||||
+++ b/include/linux/bcma/bcma_driver_gmac_cmn.h
|
||||
@@ -91,10 +91,4 @@ struct bcma_drv_gmac_cmn {
|
||||
#define gmac_cmn_write16(gc, offset, val) bcma_write16((gc)->core, offset, val)
|
||||
#define gmac_cmn_write32(gc, offset, val) bcma_write32((gc)->core, offset, val)
|
||||
|
||||
-#ifdef CONFIG_BCMA_DRIVER_GMAC_CMN
|
||||
-extern void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc);
|
||||
-#else
|
||||
-static inline void bcma_core_gmac_cmn_init(struct bcma_drv_gmac_cmn *gc) { }
|
||||
-#endif
|
||||
-
|
||||
#endif /* LINUX_BCMA_DRIVER_GMAC_CMN_H_ */
|
||||
--- a/include/linux/bcma/bcma_driver_mips.h
|
||||
+++ b/include/linux/bcma/bcma_driver_mips.h
|
||||
@@ -39,21 +39,6 @@ struct bcma_drv_mips {
|
||||
u8 early_setup_done:1;
|
||||
};
|
||||
|
||||
-#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||
-extern void bcma_core_mips_init(struct bcma_drv_mips *mcore);
|
||||
-extern void bcma_core_mips_early_init(struct bcma_drv_mips *mcore);
|
||||
-
|
||||
-extern unsigned int bcma_core_mips_irq(struct bcma_device *dev);
|
||||
-#else
|
||||
-static inline void bcma_core_mips_init(struct bcma_drv_mips *mcore) { }
|
||||
-static inline void bcma_core_mips_early_init(struct bcma_drv_mips *mcore) { }
|
||||
-
|
||||
-static inline unsigned int bcma_core_mips_irq(struct bcma_device *dev)
|
||||
-{
|
||||
- return 0;
|
||||
-}
|
||||
-#endif
|
||||
-
|
||||
extern u32 bcma_cpu_clock(struct bcma_drv_mips *mcore);
|
||||
|
||||
#endif /* LINUX_BCMA_DRIVER_MIPS_H_ */
|
@ -1,32 +0,0 @@
|
||||
--- a/include/linux/ssb/ssb.h
|
||||
+++ b/include/linux/ssb/ssb.h
|
||||
@@ -29,10 +29,13 @@ struct ssb_sprom {
|
||||
u8 il0mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11b/g */
|
||||
u8 et0mac[6] __aligned(sizeof(u16)); /* MAC address for Ethernet */
|
||||
u8 et1mac[6] __aligned(sizeof(u16)); /* MAC address for 802.11a */
|
||||
+ u8 et2mac[6] __aligned(sizeof(u16)); /* MAC address for extra Ethernet */
|
||||
u8 et0phyaddr; /* MII address for enet0 */
|
||||
u8 et1phyaddr; /* MII address for enet1 */
|
||||
+ u8 et2phyaddr; /* MII address for enet2 */
|
||||
u8 et0mdcport; /* MDIO for enet0 */
|
||||
u8 et1mdcport; /* MDIO for enet1 */
|
||||
+ u8 et2mdcport; /* MDIO for enet2 */
|
||||
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. */
|
||||
@@ -88,11 +91,14 @@ struct ssb_sprom {
|
||||
u32 ofdm5glpo; /* 5.2GHz OFDM power offset */
|
||||
u32 ofdm5gpo; /* 5.3GHz OFDM power offset */
|
||||
u32 ofdm5ghpo; /* 5.8GHz OFDM power offset */
|
||||
+ u32 boardflags;
|
||||
+ u32 boardflags2;
|
||||
+ u32 boardflags3;
|
||||
+ /* TODO: Switch all drivers to new u32 fields and drop below ones */
|
||||
u16 boardflags_lo; /* Board flags (bits 0-15) */
|
||||
u16 boardflags_hi; /* Board flags (bits 16-31) */
|
||||
u16 boardflags2_lo; /* Board flags (bits 32-47) */
|
||||
u16 boardflags2_hi; /* Board flags (bits 48-63) */
|
||||
- /* TODO store board flags in a single u64 */
|
||||
|
||||
struct ssb_sprom_core_pwr_info core_pwr_info[4];
|
||||
|
@ -1,86 +0,0 @@
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -226,6 +226,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
switch (bus->chipinfo.id) {
|
||||
+ case BCMA_CHIP_ID_BCM4707:
|
||||
case BCMA_CHIP_ID_BCM5357:
|
||||
case BCMA_CHIP_ID_BCM53572:
|
||||
chip->ngpio = 32;
|
||||
@@ -235,16 +236,17 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
}
|
||||
|
||||
/*
|
||||
- * On MIPS we register GPIO devices (LEDs, buttons) using absolute GPIO
|
||||
- * pin numbers. We don't have Device Tree there and we can't really use
|
||||
- * relative (per chip) numbers.
|
||||
- * So let's use predictable base for BCM47XX and "random" for all other.
|
||||
+ * Register SoC GPIO devices with absolute GPIO pin base.
|
||||
+ * On MIPS, we don't have Device Tree and we can't use relative (per chip)
|
||||
+ * GPIO numbers.
|
||||
+ * On some ARM devices, user space may want to access some system GPIO
|
||||
+ * pins directly, which is easier to do with a predictable GPIO base.
|
||||
*/
|
||||
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||
- chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
||||
-#else
|
||||
- chip->base = -1;
|
||||
-#endif
|
||||
+ if (IS_BUILTIN(CONFIG_BCM47XX) ||
|
||||
+ cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||
+ chip->base = bus->num * BCMA_GPIO_MAX_PINS;
|
||||
+ else
|
||||
+ chip->base = -1;
|
||||
|
||||
err = bcma_gpio_irq_domain_init(cc);
|
||||
if (err)
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -29,12 +29,6 @@ config BCMA_HOST_PCI
|
||||
select BCMA_DRIVER_PCI
|
||||
default y
|
||||
|
||||
-config BCMA_DRIVER_PCI_HOSTMODE
|
||||
- bool "Driver for PCI core working in hostmode"
|
||||
- depends on BCMA && MIPS && BCMA_HOST_PCI
|
||||
- help
|
||||
- PCI core hostmode operation (external PCI bus).
|
||||
-
|
||||
config BCMA_HOST_SOC
|
||||
bool "Support for BCMA in a SoC"
|
||||
depends on BCMA
|
||||
@@ -61,6 +55,12 @@ config BCMA_DRIVER_PCI
|
||||
This driver is also prerequisite for a hostmode PCIe core
|
||||
support.
|
||||
|
||||
+config BCMA_DRIVER_PCI_HOSTMODE
|
||||
+ bool "Driver for PCI core working in hostmode"
|
||||
+ depends on BCMA && MIPS && BCMA_DRIVER_PCI
|
||||
+ help
|
||||
+ PCI core hostmode operation (external PCI bus).
|
||||
+
|
||||
config BCMA_DRIVER_MIPS
|
||||
bool "BCMA Broadcom MIPS core driver"
|
||||
depends on BCMA && MIPS
|
||||
--- a/include/linux/bcma/bcma_driver_pci.h
|
||||
+++ b/include/linux/bcma/bcma_driver_pci.h
|
||||
@@ -246,7 +246,18 @@ static inline void bcma_core_pci_power_s
|
||||
}
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_BCMA_DRIVER_PCI_HOSTMODE
|
||||
extern int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev);
|
||||
extern int bcma_core_pci_plat_dev_init(struct pci_dev *dev);
|
||||
+#else
|
||||
+static inline int bcma_core_pci_pcibios_map_irq(const struct pci_dev *dev)
|
||||
+{
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+static inline int bcma_core_pci_plat_dev_init(struct pci_dev *dev)
|
||||
+{
|
||||
+ return -ENOTSUPP;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
#endif /* LINUX_BCMA_DRIVER_PCI_H_ */
|
@ -1,509 +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
|
||||
@@ -106,6 +106,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,391 @@
|
||||
+/* 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(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;
|
||||
+ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ spin_lock_bh(&pcpu->lock);
|
||||
+
|
||||
+ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
|
||||
+ ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
+ if (nf_ct_rtcache_find(ct) != NULL) {
|
||||
+ wait = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ spin_unlock_bh(&pcpu->lock);
|
||||
+ rcu_read_unlock();
|
||||
+ }
|
||||
+
|
||||
+ return wait;
|
||||
+}
|
||||
+
|
||||
+static void __exit nf_conntrack_rtcache_fini(void)
|
||||
+{
|
||||
+ struct net *net;
|
||||
+ int count = 0;
|
||||
+
|
||||
+ /* remove hooks so no new connections get rtcache extension */
|
||||
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+
|
||||
+ synchronize_net();
|
||||
+
|
||||
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
+ /* zap all conntracks with rtcache extension */
|
||||
+ for_each_net(net)
|
||||
+ nf_ct_iterate_cleanup(net, nf_rtcache_ext_remove, NULL, 0, 0);
|
||||
+
|
||||
+ for_each_net(net) {
|
||||
+ /* .. and make sure they're gone from dying list, too */
|
||||
+ while (nf_conntrack_rtcache_wait_for_dying(net)) {
|
||||
+ msleep(200);
|
||||
+ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+ synchronize_net();
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+}
|
||||
+module_init(nf_conntrack_rtcache_init);
|
||||
+module_exit(nf_conntrack_rtcache_fini);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
|
||||
+MODULE_DESCRIPTION("Conntrack route cache extension");
|
@ -1,22 +0,0 @@
|
||||
--- a/arch/mips/boot/compressed/string.c
|
||||
+++ b/arch/mips/boot/compressed/string.c
|
||||
@@ -26,3 +26,19 @@ void *memset(void *s, int c, size_t n)
|
||||
ss[i] = c;
|
||||
return s;
|
||||
}
|
||||
+
|
||||
+void *memmove(void *__dest, __const void *__src, size_t count)
|
||||
+{
|
||||
+ unsigned char *d = __dest;
|
||||
+ const unsigned char *s = __src;
|
||||
+
|
||||
+ if (__dest == __src)
|
||||
+ return __dest;
|
||||
+
|
||||
+ if (__dest < __src)
|
||||
+ return memcpy(__dest, __src, count);
|
||||
+
|
||||
+ while (count--)
|
||||
+ d[count] = s[count];
|
||||
+ return __dest;
|
||||
+}
|
@ -1,76 +0,0 @@
|
||||
From c25b23b8a387e7d31f7a74af8e37b61e9e6ebb21 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Fri, 20 Mar 2015 23:14:31 +0100
|
||||
Subject: [PATCH] bgmac: register fixed PHY for ARM BCM470X / BCM5301X chipsets
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
On ARM SoCs with bgmac Ethernet hardware we don't have any normal PHY.
|
||||
There is always a switch attached but it's not even controlled over MDIO
|
||||
like in case of MIPS devices.
|
||||
We need a fixed PHY to be able to send/receive packets from the switch.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 34 ++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 34 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/mii.h>
|
||||
#include <linux/phy.h>
|
||||
+#include <linux/phy_fixed.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/dma-mapping.h>
|
||||
#include <bcm47xx_nvram.h>
|
||||
@@ -1330,13 +1331,46 @@ static void bgmac_adjust_link(struct net
|
||||
}
|
||||
}
|
||||
|
||||
+static int bgmac_fixed_phy_register(struct bgmac *bgmac)
|
||||
+{
|
||||
+ struct fixed_phy_status fphy_status = {
|
||||
+ .link = 1,
|
||||
+ .speed = SPEED_1000,
|
||||
+ .duplex = DUPLEX_FULL,
|
||||
+ };
|
||||
+ struct phy_device *phy_dev;
|
||||
+ int err;
|
||||
+
|
||||
+ phy_dev = fixed_phy_register(PHY_POLL, &fphy_status, NULL);
|
||||
+ if (!phy_dev || IS_ERR(phy_dev)) {
|
||||
+ bgmac_err(bgmac, "Failed to register fixed PHY device\n");
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ err = phy_connect_direct(bgmac->net_dev, phy_dev, bgmac_adjust_link,
|
||||
+ PHY_INTERFACE_MODE_MII);
|
||||
+ if (err) {
|
||||
+ bgmac_err(bgmac, "Connecting PHY failed\n");
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+ bgmac->phy_dev = phy_dev;
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static int bgmac_mii_register(struct bgmac *bgmac)
|
||||
{
|
||||
+ struct bcma_chipinfo *ci = &bgmac->core->bus->chipinfo;
|
||||
struct mii_bus *mii_bus;
|
||||
struct phy_device *phy_dev;
|
||||
char bus_id[MII_BUS_ID_SIZE + 3];
|
||||
int i, err = 0;
|
||||
|
||||
+ if (ci->id == BCMA_CHIP_ID_BCM4707 ||
|
||||
+ ci->id == BCMA_CHIP_ID_BCM53018)
|
||||
+ return bgmac_fixed_phy_register(bgmac);
|
||||
+
|
||||
mii_bus = mdiobus_alloc();
|
||||
if (!mii_bus)
|
||||
return -ENOMEM;
|
@ -1,28 +0,0 @@
|
||||
From fc300dc3733fdc328e6e10c7b8379b60c26cd648 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Fri, 20 Mar 2015 23:14:32 +0100
|
||||
Subject: [PATCH] bgmac: allow enabling on ARCH_BCM_5301X
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Home routers based on ARM SoCs like BCM4708 also have bcma bus with core
|
||||
supported by bgmac.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/Kconfig
|
||||
+++ b/drivers/net/ethernet/broadcom/Kconfig
|
||||
@@ -142,7 +142,7 @@ config BNX2X_SRIOV
|
||||
|
||||
config BGMAC
|
||||
tristate "BCMA bus GBit core support"
|
||||
- depends on BCMA_HOST_SOC && HAS_DMA && BCM47XX
|
||||
+ depends on BCMA_HOST_SOC && HAS_DMA && (BCM47XX || ARCH_BCM_5301X)
|
||||
select PHYLIB
|
||||
---help---
|
||||
This driver supports GBit MAC and BCM4706 GBit MAC cores on BCMA bus.
|
@ -1,24 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 23 Mar 2015 02:40:06 +0100
|
||||
Subject: [PATCH] bgmac: fix descriptor frame start/end definitions
|
||||
|
||||
The start-of-frame and end-of-frame bits were accidentally swapped.
|
||||
In the current code it does not make any difference, since they are
|
||||
always used together.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -345,8 +345,8 @@
|
||||
|
||||
#define BGMAC_DESC_CTL0_EOT 0x10000000 /* End of ring */
|
||||
#define BGMAC_DESC_CTL0_IOC 0x20000000 /* IRQ on complete */
|
||||
-#define BGMAC_DESC_CTL0_SOF 0x40000000 /* Start of frame */
|
||||
-#define BGMAC_DESC_CTL0_EOF 0x80000000 /* End of frame */
|
||||
+#define BGMAC_DESC_CTL0_EOF 0x40000000 /* End of frame */
|
||||
+#define BGMAC_DESC_CTL0_SOF 0x80000000 /* Start of frame */
|
||||
#define BGMAC_DESC_CTL1_LEN 0x00001FFF
|
||||
|
||||
#define BGMAC_PHY_NOREGS 0x1E
|
@ -1,189 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 23 Mar 2015 02:41:25 +0100
|
||||
Subject: [PATCH] bgmac: implement GRO and use build_skb
|
||||
|
||||
This improves performance for routing and local rx
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -276,31 +276,31 @@ static int bgmac_dma_rx_skb_for_slot(str
|
||||
struct bgmac_slot_info *slot)
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
- struct sk_buff *skb;
|
||||
dma_addr_t dma_addr;
|
||||
struct bgmac_rx_header *rx;
|
||||
+ void *buf;
|
||||
|
||||
/* Alloc skb */
|
||||
- skb = netdev_alloc_skb(bgmac->net_dev, BGMAC_RX_BUF_SIZE);
|
||||
- if (!skb)
|
||||
+ buf = netdev_alloc_frag(BGMAC_RX_ALLOC_SIZE);
|
||||
+ if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
/* Poison - if everything goes fine, hardware will overwrite it */
|
||||
- rx = (struct bgmac_rx_header *)skb->data;
|
||||
+ rx = buf;
|
||||
rx->len = cpu_to_le16(0xdead);
|
||||
rx->flags = cpu_to_le16(0xbeef);
|
||||
|
||||
/* Map skb for the DMA */
|
||||
- dma_addr = dma_map_single(dma_dev, skb->data,
|
||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
+ dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
|
||||
+ DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dma_dev, dma_addr)) {
|
||||
bgmac_err(bgmac, "DMA mapping error\n");
|
||||
- dev_kfree_skb(skb);
|
||||
+ put_page(virt_to_head_page(buf));
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* Update the slot */
|
||||
- slot->skb = skb;
|
||||
+ slot->buf = buf;
|
||||
slot->dma_addr = dma_addr;
|
||||
|
||||
return 0;
|
||||
@@ -343,8 +343,9 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
while (ring->start != ring->end) {
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
- struct sk_buff *skb = slot->skb;
|
||||
- struct bgmac_rx_header *rx;
|
||||
+ struct bgmac_rx_header *rx = slot->buf;
|
||||
+ struct sk_buff *skb;
|
||||
+ void *buf = slot->buf;
|
||||
u16 len, flags;
|
||||
|
||||
/* Unmap buffer to make it accessible to the CPU */
|
||||
@@ -352,7 +353,6 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
/* Get info from the header */
|
||||
- rx = (struct bgmac_rx_header *)skb->data;
|
||||
len = le16_to_cpu(rx->len);
|
||||
flags = le16_to_cpu(rx->flags);
|
||||
|
||||
@@ -393,12 +393,13 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
dma_unmap_single(dma_dev, old_dma_addr,
|
||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
+ skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
||||
skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
|
||||
skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
|
||||
|
||||
skb_checksum_none_assert(skb);
|
||||
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
|
||||
- netif_receive_skb(skb);
|
||||
+ napi_gro_receive(&bgmac->napi, skb);
|
||||
handled++;
|
||||
} while (0);
|
||||
|
||||
@@ -434,12 +435,11 @@ static bool bgmac_dma_unaligned(struct b
|
||||
return false;
|
||||
}
|
||||
|
||||
-static void bgmac_dma_ring_free(struct bgmac *bgmac,
|
||||
- struct bgmac_dma_ring *ring)
|
||||
+static void bgmac_dma_tx_ring_free(struct bgmac *bgmac,
|
||||
+ struct bgmac_dma_ring *ring)
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct bgmac_slot_info *slot;
|
||||
- int size;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ring->num_slots; i++) {
|
||||
@@ -451,23 +451,55 @@ static void bgmac_dma_ring_free(struct b
|
||||
dev_kfree_skb(slot->skb);
|
||||
}
|
||||
}
|
||||
+}
|
||||
+
|
||||
+static void bgmac_dma_rx_ring_free(struct bgmac *bgmac,
|
||||
+ struct bgmac_dma_ring *ring)
|
||||
+{
|
||||
+ struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct bgmac_slot_info *slot;
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < ring->num_slots; i++) {
|
||||
+ slot = &ring->slots[i];
|
||||
+ if (!slot->buf)
|
||||
+ continue;
|
||||
|
||||
- if (ring->cpu_base) {
|
||||
- /* Free ring of descriptors */
|
||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
||||
- dma_free_coherent(dma_dev, size, ring->cpu_base,
|
||||
- ring->dma_base);
|
||||
+ if (slot->dma_addr)
|
||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
+ BGMAC_RX_BUF_SIZE,
|
||||
+ DMA_FROM_DEVICE);
|
||||
+ put_page(virt_to_head_page(slot->buf));
|
||||
}
|
||||
}
|
||||
|
||||
+static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
|
||||
+ struct bgmac_dma_ring *ring)
|
||||
+{
|
||||
+ struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ int size;
|
||||
+
|
||||
+ if (!ring->cpu_base)
|
||||
+ return;
|
||||
+
|
||||
+ /* Free ring of descriptors */
|
||||
+ size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
||||
+ dma_free_coherent(dma_dev, size, ring->cpu_base,
|
||||
+ ring->dma_base);
|
||||
+}
|
||||
+
|
||||
static void bgmac_dma_free(struct bgmac *bgmac)
|
||||
{
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
||||
- bgmac_dma_ring_free(bgmac, &bgmac->tx_ring[i]);
|
||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
||||
- bgmac_dma_ring_free(bgmac, &bgmac->rx_ring[i]);
|
||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
||||
+ bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
|
||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
||||
+ }
|
||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
||||
+ bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
|
||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
||||
+ }
|
||||
}
|
||||
|
||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -362,6 +362,8 @@
|
||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
||||
#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
|
||||
#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
|
||||
+#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
|
||||
+ SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
|
||||
#define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
|
||||
#define BGMAC_BFL_ENETADM 0x0080 /* has ADMtek switch */
|
||||
@@ -383,7 +385,10 @@
|
||||
#define ETHER_MAX_LEN 1518
|
||||
|
||||
struct bgmac_slot_info {
|
||||
- struct sk_buff *skb;
|
||||
+ union {
|
||||
+ struct sk_buff *skb;
|
||||
+ void *buf;
|
||||
+ };
|
||||
dma_addr_t dma_addr;
|
||||
};
|
||||
|
@ -1,267 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 23 Mar 2015 02:42:26 +0100
|
||||
Subject: [PATCH] bgmac: implement scatter/gather support
|
||||
|
||||
Always use software checksumming, since the hardware does not have any
|
||||
checksum offload support.
|
||||
This significantly improves local TCP tx performance.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -115,53 +115,91 @@ static void bgmac_dma_tx_enable(struct b
|
||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_CTL, ctl);
|
||||
}
|
||||
|
||||
+static void
|
||||
+bgmac_dma_tx_add_buf(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
|
||||
+ int i, int len, u32 ctl0)
|
||||
+{
|
||||
+ struct bgmac_slot_info *slot;
|
||||
+ struct bgmac_dma_desc *dma_desc;
|
||||
+ u32 ctl1;
|
||||
+
|
||||
+ if (i == ring->num_slots - 1)
|
||||
+ ctl0 |= BGMAC_DESC_CTL0_EOT;
|
||||
+
|
||||
+ ctl1 = len & BGMAC_DESC_CTL1_LEN;
|
||||
+
|
||||
+ slot = &ring->slots[i];
|
||||
+ dma_desc = &ring->cpu_base[i];
|
||||
+ dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
|
||||
+ dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
|
||||
+ dma_desc->ctl0 = cpu_to_le32(ctl0);
|
||||
+ dma_desc->ctl1 = cpu_to_le32(ctl1);
|
||||
+}
|
||||
+
|
||||
static netdev_tx_t bgmac_dma_tx_add(struct bgmac *bgmac,
|
||||
struct bgmac_dma_ring *ring,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct net_device *net_dev = bgmac->net_dev;
|
||||
- struct bgmac_dma_desc *dma_desc;
|
||||
- struct bgmac_slot_info *slot;
|
||||
- u32 ctl0, ctl1;
|
||||
+ struct bgmac_slot_info *slot = &ring->slots[ring->end];
|
||||
int free_slots;
|
||||
+ int nr_frags;
|
||||
+ u32 flags;
|
||||
+ int index = ring->end;
|
||||
+ int i;
|
||||
|
||||
if (skb->len > BGMAC_DESC_CTL1_LEN) {
|
||||
bgmac_err(bgmac, "Too long skb (%d)\n", skb->len);
|
||||
- goto err_stop_drop;
|
||||
+ goto err_drop;
|
||||
}
|
||||
|
||||
+ if (skb->ip_summed == CHECKSUM_PARTIAL)
|
||||
+ skb_checksum_help(skb);
|
||||
+
|
||||
+ nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
+
|
||||
if (ring->start <= ring->end)
|
||||
free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
|
||||
else
|
||||
free_slots = ring->start - ring->end;
|
||||
- if (free_slots == 1) {
|
||||
+
|
||||
+ if (free_slots <= nr_frags + 1) {
|
||||
bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
|
||||
netif_stop_queue(net_dev);
|
||||
return NETDEV_TX_BUSY;
|
||||
}
|
||||
|
||||
- slot = &ring->slots[ring->end];
|
||||
- slot->skb = skb;
|
||||
- slot->dma_addr = dma_map_single(dma_dev, skb->data, skb->len,
|
||||
+ slot->dma_addr = dma_map_single(dma_dev, skb->data, skb_headlen(skb),
|
||||
DMA_TO_DEVICE);
|
||||
- if (dma_mapping_error(dma_dev, slot->dma_addr)) {
|
||||
- bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
|
||||
- ring->mmio_base);
|
||||
- goto err_stop_drop;
|
||||
- }
|
||||
+ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
|
||||
+ goto err_dma_head;
|
||||
|
||||
- ctl0 = BGMAC_DESC_CTL0_IOC | BGMAC_DESC_CTL0_SOF | BGMAC_DESC_CTL0_EOF;
|
||||
- if (ring->end == ring->num_slots - 1)
|
||||
- ctl0 |= BGMAC_DESC_CTL0_EOT;
|
||||
- ctl1 = skb->len & BGMAC_DESC_CTL1_LEN;
|
||||
+ flags = BGMAC_DESC_CTL0_SOF;
|
||||
+ if (!nr_frags)
|
||||
+ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
|
||||
+
|
||||
+ bgmac_dma_tx_add_buf(bgmac, ring, index, skb_headlen(skb), flags);
|
||||
+ flags = 0;
|
||||
+
|
||||
+ for (i = 0; i < nr_frags; i++) {
|
||||
+ struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[i];
|
||||
+ int len = skb_frag_size(frag);
|
||||
+
|
||||
+ index = (index + 1) % BGMAC_TX_RING_SLOTS;
|
||||
+ slot = &ring->slots[index];
|
||||
+ slot->dma_addr = skb_frag_dma_map(dma_dev, frag, 0,
|
||||
+ len, DMA_TO_DEVICE);
|
||||
+ if (unlikely(dma_mapping_error(dma_dev, slot->dma_addr)))
|
||||
+ goto err_dma;
|
||||
|
||||
- dma_desc = ring->cpu_base;
|
||||
- dma_desc += ring->end;
|
||||
- dma_desc->addr_low = cpu_to_le32(lower_32_bits(slot->dma_addr));
|
||||
- dma_desc->addr_high = cpu_to_le32(upper_32_bits(slot->dma_addr));
|
||||
- dma_desc->ctl0 = cpu_to_le32(ctl0);
|
||||
- dma_desc->ctl1 = cpu_to_le32(ctl1);
|
||||
+ if (i == nr_frags - 1)
|
||||
+ flags |= BGMAC_DESC_CTL0_EOF | BGMAC_DESC_CTL0_IOC;
|
||||
+
|
||||
+ bgmac_dma_tx_add_buf(bgmac, ring, index, len, flags);
|
||||
+ }
|
||||
+
|
||||
+ slot->skb = skb;
|
||||
|
||||
netdev_sent_queue(net_dev, skb->len);
|
||||
|
||||
@@ -170,20 +208,35 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
/* Increase ring->end to point empty slot. We tell hardware the first
|
||||
* slot it should *not* read.
|
||||
*/
|
||||
- if (++ring->end >= BGMAC_TX_RING_SLOTS)
|
||||
- ring->end = 0;
|
||||
+ ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
|
||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
|
||||
ring->index_base +
|
||||
ring->end * sizeof(struct bgmac_dma_desc));
|
||||
|
||||
- /* Always keep one slot free to allow detecting bugged calls. */
|
||||
- if (--free_slots == 1)
|
||||
+ free_slots -= nr_frags + 1;
|
||||
+ if (free_slots < 8)
|
||||
netif_stop_queue(net_dev);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
|
||||
-err_stop_drop:
|
||||
- netif_stop_queue(net_dev);
|
||||
+err_dma:
|
||||
+ dma_unmap_single(dma_dev, slot->dma_addr, skb_headlen(skb),
|
||||
+ DMA_TO_DEVICE);
|
||||
+
|
||||
+ while (i > 0) {
|
||||
+ int index = (ring->end + i) % BGMAC_TX_RING_SLOTS;
|
||||
+ struct bgmac_slot_info *slot = &ring->slots[index];
|
||||
+ u32 ctl1 = le32_to_cpu(ring->cpu_base[index].ctl1);
|
||||
+ int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
+
|
||||
+ dma_unmap_page(dma_dev, slot->dma_addr, len, DMA_TO_DEVICE);
|
||||
+ }
|
||||
+
|
||||
+err_dma_head:
|
||||
+ bgmac_err(bgmac, "Mapping error of skb on ring 0x%X\n",
|
||||
+ ring->mmio_base);
|
||||
+
|
||||
+err_drop:
|
||||
dev_kfree_skb(skb);
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
@@ -205,32 +258,45 @@ static void bgmac_dma_tx_free(struct bgm
|
||||
|
||||
while (ring->start != empty_slot) {
|
||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
+ u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
|
||||
+ int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
|
||||
- if (slot->skb) {
|
||||
+ if (!slot->dma_addr) {
|
||||
+ bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
||||
+ ring->start, ring->end);
|
||||
+ goto next;
|
||||
+ }
|
||||
+
|
||||
+ if (ctl1 & BGMAC_DESC_CTL0_SOF)
|
||||
/* Unmap no longer used buffer */
|
||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
- slot->skb->len, DMA_TO_DEVICE);
|
||||
- slot->dma_addr = 0;
|
||||
+ dma_unmap_single(dma_dev, slot->dma_addr, len,
|
||||
+ DMA_TO_DEVICE);
|
||||
+ else
|
||||
+ dma_unmap_page(dma_dev, slot->dma_addr, len,
|
||||
+ DMA_TO_DEVICE);
|
||||
|
||||
+ if (slot->skb) {
|
||||
bytes_compl += slot->skb->len;
|
||||
pkts_compl++;
|
||||
|
||||
/* Free memory! :) */
|
||||
dev_kfree_skb(slot->skb);
|
||||
slot->skb = NULL;
|
||||
- } else {
|
||||
- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
||||
- ring->start, ring->end);
|
||||
}
|
||||
|
||||
+next:
|
||||
+ slot->dma_addr = 0;
|
||||
if (++ring->start >= BGMAC_TX_RING_SLOTS)
|
||||
ring->start = 0;
|
||||
freed = true;
|
||||
}
|
||||
|
||||
+ if (!pkts_compl)
|
||||
+ return;
|
||||
+
|
||||
netdev_completed_queue(bgmac->net_dev, pkts_compl, bytes_compl);
|
||||
|
||||
- if (freed && netif_queue_stopped(bgmac->net_dev))
|
||||
+ if (netif_queue_stopped(bgmac->net_dev))
|
||||
netif_wake_queue(bgmac->net_dev);
|
||||
}
|
||||
|
||||
@@ -439,17 +505,25 @@ static void bgmac_dma_tx_ring_free(struc
|
||||
struct bgmac_dma_ring *ring)
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
+ struct bgmac_dma_desc *dma_desc = ring->cpu_base;
|
||||
struct bgmac_slot_info *slot;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ring->num_slots; i++) {
|
||||
+ int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
+
|
||||
slot = &ring->slots[i];
|
||||
- if (slot->skb) {
|
||||
- if (slot->dma_addr)
|
||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
- slot->skb->len, DMA_TO_DEVICE);
|
||||
- dev_kfree_skb(slot->skb);
|
||||
- }
|
||||
+ dev_kfree_skb(slot->skb);
|
||||
+
|
||||
+ if (!slot->dma_addr)
|
||||
+ continue;
|
||||
+
|
||||
+ if (slot->skb)
|
||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
+ len, DMA_TO_DEVICE);
|
||||
+ else
|
||||
+ dma_unmap_page(dma_dev, slot->dma_addr,
|
||||
+ len, DMA_TO_DEVICE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1583,6 +1657,10 @@ static int bgmac_probe(struct bcma_devic
|
||||
goto err_dma_free;
|
||||
}
|
||||
|
||||
+ net_dev->features = NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
|
||||
+ net_dev->hw_features = net_dev->features;
|
||||
+ net_dev->vlan_features = net_dev->features;
|
||||
+
|
||||
err = register_netdev(bgmac->net_dev);
|
||||
if (err) {
|
||||
bgmac_err(bgmac, "Cannot register net device\n");
|
@ -1,125 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 09:58:56 +0200
|
||||
Subject: [PATCH] bgmac: simplify tx ring index handling
|
||||
|
||||
Keep incrementing ring->start and ring->end instead of pointing it to
|
||||
the actual ring slot entry. This simplifies the calculation of the
|
||||
number of free slots.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -142,11 +142,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct net_device *net_dev = bgmac->net_dev;
|
||||
- struct bgmac_slot_info *slot = &ring->slots[ring->end];
|
||||
- int free_slots;
|
||||
+ int index = ring->end % BGMAC_TX_RING_SLOTS;
|
||||
+ struct bgmac_slot_info *slot = &ring->slots[index];
|
||||
int nr_frags;
|
||||
u32 flags;
|
||||
- int index = ring->end;
|
||||
int i;
|
||||
|
||||
if (skb->len > BGMAC_DESC_CTL1_LEN) {
|
||||
@@ -159,12 +158,10 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
|
||||
nr_frags = skb_shinfo(skb)->nr_frags;
|
||||
|
||||
- if (ring->start <= ring->end)
|
||||
- free_slots = ring->start - ring->end + BGMAC_TX_RING_SLOTS;
|
||||
- else
|
||||
- free_slots = ring->start - ring->end;
|
||||
-
|
||||
- if (free_slots <= nr_frags + 1) {
|
||||
+ /* ring->end - ring->start will return the number of valid slots,
|
||||
+ * even when ring->end overflows
|
||||
+ */
|
||||
+ if (ring->end - ring->start + nr_frags + 1 >= BGMAC_TX_RING_SLOTS) {
|
||||
bgmac_err(bgmac, "TX ring is full, queue should be stopped!\n");
|
||||
netif_stop_queue(net_dev);
|
||||
return NETDEV_TX_BUSY;
|
||||
@@ -200,7 +197,7 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
}
|
||||
|
||||
slot->skb = skb;
|
||||
-
|
||||
+ ring->end += nr_frags + 1;
|
||||
netdev_sent_queue(net_dev, skb->len);
|
||||
|
||||
wmb();
|
||||
@@ -208,13 +205,12 @@ static netdev_tx_t bgmac_dma_tx_add(stru
|
||||
/* Increase ring->end to point empty slot. We tell hardware the first
|
||||
* slot it should *not* read.
|
||||
*/
|
||||
- ring->end = (index + 1) % BGMAC_TX_RING_SLOTS;
|
||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_TX_INDEX,
|
||||
ring->index_base +
|
||||
- ring->end * sizeof(struct bgmac_dma_desc));
|
||||
+ (ring->end % BGMAC_TX_RING_SLOTS) *
|
||||
+ sizeof(struct bgmac_dma_desc));
|
||||
|
||||
- free_slots -= nr_frags + 1;
|
||||
- if (free_slots < 8)
|
||||
+ if (ring->end - ring->start >= BGMAC_TX_RING_SLOTS - 8)
|
||||
netif_stop_queue(net_dev);
|
||||
|
||||
return NETDEV_TX_OK;
|
||||
@@ -256,17 +252,17 @@ static void bgmac_dma_tx_free(struct bgm
|
||||
empty_slot &= BGMAC_DMA_TX_STATDPTR;
|
||||
empty_slot /= sizeof(struct bgmac_dma_desc);
|
||||
|
||||
- while (ring->start != empty_slot) {
|
||||
- struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
- u32 ctl1 = le32_to_cpu(ring->cpu_base[ring->start].ctl1);
|
||||
- int len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
+ while (ring->start != ring->end) {
|
||||
+ int slot_idx = ring->start % BGMAC_TX_RING_SLOTS;
|
||||
+ struct bgmac_slot_info *slot = &ring->slots[slot_idx];
|
||||
+ u32 ctl1;
|
||||
+ int len;
|
||||
|
||||
- if (!slot->dma_addr) {
|
||||
- bgmac_err(bgmac, "Hardware reported transmission for empty TX ring slot %d! End of ring: %d\n",
|
||||
- ring->start, ring->end);
|
||||
- goto next;
|
||||
- }
|
||||
+ if (slot_idx == empty_slot)
|
||||
+ break;
|
||||
|
||||
+ ctl1 = le32_to_cpu(ring->cpu_base[slot_idx].ctl1);
|
||||
+ len = ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
if (ctl1 & BGMAC_DESC_CTL0_SOF)
|
||||
/* Unmap no longer used buffer */
|
||||
dma_unmap_single(dma_dev, slot->dma_addr, len,
|
||||
@@ -284,10 +280,8 @@ static void bgmac_dma_tx_free(struct bgm
|
||||
slot->skb = NULL;
|
||||
}
|
||||
|
||||
-next:
|
||||
slot->dma_addr = 0;
|
||||
- if (++ring->start >= BGMAC_TX_RING_SLOTS)
|
||||
- ring->start = 0;
|
||||
+ ring->start++;
|
||||
freed = true;
|
||||
}
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -414,10 +414,10 @@ enum bgmac_dma_ring_type {
|
||||
* empty.
|
||||
*/
|
||||
struct bgmac_dma_ring {
|
||||
- u16 num_slots;
|
||||
- u16 start;
|
||||
- u16 end;
|
||||
+ u32 start;
|
||||
+ u32 end;
|
||||
|
||||
+ u16 num_slots;
|
||||
u16 mmio_base;
|
||||
struct bgmac_dma_desc *cpu_base;
|
||||
dma_addr_t dma_base;
|
@ -1,87 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 10:08:04 +0200
|
||||
Subject: [PATCH] bgmac: leave interrupts disabled as long as there is work
|
||||
to do
|
||||
|
||||
Always poll rx and tx during NAPI poll instead of relying on the status
|
||||
of the first interrupt. This prevents bgmac_poll from leaving unfinished
|
||||
work around until the next IRQ.
|
||||
In my tests this makes bridging/routing throughput under heavy load more
|
||||
stable and ensures that no new IRQs arrive as long as bgmac_poll uses up
|
||||
the entire budget.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1109,8 +1109,6 @@ static void bgmac_chip_reset(struct bgma
|
||||
bgmac_phy_init(bgmac);
|
||||
|
||||
netdev_reset_queue(bgmac->net_dev);
|
||||
-
|
||||
- bgmac->int_status = 0;
|
||||
}
|
||||
|
||||
static void bgmac_chip_intrs_on(struct bgmac *bgmac)
|
||||
@@ -1225,14 +1223,13 @@ static irqreturn_t bgmac_interrupt(int i
|
||||
if (!int_status)
|
||||
return IRQ_NONE;
|
||||
|
||||
- /* Ack */
|
||||
- bgmac_write(bgmac, BGMAC_INT_STATUS, int_status);
|
||||
+ int_status &= ~(BGMAC_IS_TX0 | BGMAC_IS_RX);
|
||||
+ if (int_status)
|
||||
+ bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", int_status);
|
||||
|
||||
/* Disable new interrupts until handling existing ones */
|
||||
bgmac_chip_intrs_off(bgmac);
|
||||
|
||||
- bgmac->int_status = int_status;
|
||||
-
|
||||
napi_schedule(&bgmac->napi);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
@@ -1241,25 +1238,17 @@ static irqreturn_t bgmac_interrupt(int i
|
||||
static int bgmac_poll(struct napi_struct *napi, int weight)
|
||||
{
|
||||
struct bgmac *bgmac = container_of(napi, struct bgmac, napi);
|
||||
- struct bgmac_dma_ring *ring;
|
||||
int handled = 0;
|
||||
|
||||
- if (bgmac->int_status & BGMAC_IS_TX0) {
|
||||
- ring = &bgmac->tx_ring[0];
|
||||
- bgmac_dma_tx_free(bgmac, ring);
|
||||
- bgmac->int_status &= ~BGMAC_IS_TX0;
|
||||
- }
|
||||
+ /* Ack */
|
||||
+ bgmac_write(bgmac, BGMAC_INT_STATUS, ~0);
|
||||
|
||||
- if (bgmac->int_status & BGMAC_IS_RX) {
|
||||
- ring = &bgmac->rx_ring[0];
|
||||
- handled += bgmac_dma_rx_read(bgmac, ring, weight);
|
||||
- bgmac->int_status &= ~BGMAC_IS_RX;
|
||||
- }
|
||||
+ bgmac_dma_tx_free(bgmac, &bgmac->tx_ring[0]);
|
||||
+ handled += bgmac_dma_rx_read(bgmac, &bgmac->rx_ring[0], weight);
|
||||
|
||||
- if (bgmac->int_status) {
|
||||
- bgmac_err(bgmac, "Unknown IRQs: 0x%08X\n", bgmac->int_status);
|
||||
- bgmac->int_status = 0;
|
||||
- }
|
||||
+ /* Poll again if more events arrived in the meantime */
|
||||
+ if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX))
|
||||
+ return handled;
|
||||
|
||||
if (handled < weight) {
|
||||
napi_complete(napi);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -452,7 +452,6 @@ struct bgmac {
|
||||
|
||||
/* Int */
|
||||
u32 int_mask;
|
||||
- u32 int_status;
|
||||
|
||||
/* Current MAC state */
|
||||
int mac_speed;
|
@ -1,66 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 10:13:28 +0200
|
||||
Subject: [PATCH] bgmac: set received skb headroom to NET_SKB_PAD
|
||||
|
||||
A packet buffer offset of 30 bytes is inefficient, because the first 2
|
||||
bytes end up in a different cacheline.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -346,13 +346,13 @@ static int bgmac_dma_rx_skb_for_slot(str
|
||||
return -ENOMEM;
|
||||
|
||||
/* Poison - if everything goes fine, hardware will overwrite it */
|
||||
- rx = buf;
|
||||
+ rx = buf + BGMAC_RX_BUF_OFFSET;
|
||||
rx->len = cpu_to_le16(0xdead);
|
||||
rx->flags = cpu_to_le16(0xbeef);
|
||||
|
||||
/* Map skb for the DMA */
|
||||
- dma_addr = dma_map_single(dma_dev, buf, BGMAC_RX_BUF_SIZE,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ dma_addr = dma_map_single(dma_dev, buf + BGMAC_RX_BUF_OFFSET,
|
||||
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
if (dma_mapping_error(dma_dev, dma_addr)) {
|
||||
bgmac_err(bgmac, "DMA mapping error\n");
|
||||
put_page(virt_to_head_page(buf));
|
||||
@@ -403,7 +403,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
while (ring->start != ring->end) {
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
- struct bgmac_rx_header *rx = slot->buf;
|
||||
+ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
||||
struct sk_buff *skb;
|
||||
void *buf = slot->buf;
|
||||
u16 len, flags;
|
||||
@@ -454,8 +454,10 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
|
||||
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
||||
- skb_put(skb, BGMAC_RX_FRAME_OFFSET + len);
|
||||
- skb_pull(skb, BGMAC_RX_FRAME_OFFSET);
|
||||
+ skb_put(skb, BGMAC_RX_FRAME_OFFSET +
|
||||
+ BGMAC_RX_BUF_OFFSET + len);
|
||||
+ skb_pull(skb, BGMAC_RX_FRAME_OFFSET +
|
||||
+ BGMAC_RX_BUF_OFFSET);
|
||||
|
||||
skb_checksum_none_assert(skb);
|
||||
skb->protocol = eth_type_trans(skb, bgmac->net_dev);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -360,9 +360,11 @@
|
||||
|
||||
#define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */
|
||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
||||
+#define BGMAC_RX_BUF_OFFSET (NET_SKB_PAD + NET_IP_ALIGN - \
|
||||
+ BGMAC_RX_FRAME_OFFSET)
|
||||
#define BGMAC_RX_MAX_FRAME_SIZE 1536 /* Copied from b44/tg3 */
|
||||
#define BGMAC_RX_BUF_SIZE (BGMAC_RX_FRAME_OFFSET + BGMAC_RX_MAX_FRAME_SIZE)
|
||||
-#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE) + \
|
||||
+#define BGMAC_RX_ALLOC_SIZE (SKB_DATA_ALIGN(BGMAC_RX_BUF_SIZE + BGMAC_RX_BUF_OFFSET) + \
|
||||
SKB_DATA_ALIGN(sizeof(struct skb_shared_info)))
|
||||
|
||||
#define BGMAC_BFL_ENETROBO 0x0010 /* has ephy roboswitch spi */
|
@ -1,130 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 22:23:07 +0200
|
||||
Subject: [PATCH] bgmac: simplify/optimize rx DMA error handling
|
||||
|
||||
Allocate a new buffer before processing the completed one. If allocation
|
||||
fails, reuse the old buffer.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -386,6 +386,19 @@ static void bgmac_dma_rx_setup_desc(stru
|
||||
dma_desc->ctl1 = cpu_to_le32(ctl1);
|
||||
}
|
||||
|
||||
+static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
|
||||
+ struct bgmac_slot_info *slot)
|
||||
+{
|
||||
+ struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
||||
+
|
||||
+ dma_sync_single_for_cpu(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
|
||||
+ DMA_FROM_DEVICE);
|
||||
+ rx->len = cpu_to_le16(0xdead);
|
||||
+ rx->flags = cpu_to_le16(0xbeef);
|
||||
+ dma_sync_single_for_device(dma_dev, slot->dma_addr, BGMAC_RX_BUF_SIZE,
|
||||
+ DMA_FROM_DEVICE);
|
||||
+}
|
||||
+
|
||||
static int bgmac_dma_rx_read(struct bgmac *bgmac, struct bgmac_dma_ring *ring,
|
||||
int weight)
|
||||
{
|
||||
@@ -406,53 +419,35 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
||||
struct sk_buff *skb;
|
||||
void *buf = slot->buf;
|
||||
+ dma_addr_t dma_addr = slot->dma_addr;
|
||||
u16 len, flags;
|
||||
|
||||
- /* Unmap buffer to make it accessible to the CPU */
|
||||
- dma_sync_single_for_cpu(dma_dev, slot->dma_addr,
|
||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
-
|
||||
- /* Get info from the header */
|
||||
- len = le16_to_cpu(rx->len);
|
||||
- flags = le16_to_cpu(rx->flags);
|
||||
-
|
||||
do {
|
||||
- dma_addr_t old_dma_addr = slot->dma_addr;
|
||||
- int err;
|
||||
+ /* Prepare new skb as replacement */
|
||||
+ if (bgmac_dma_rx_skb_for_slot(bgmac, slot)) {
|
||||
+ bgmac_dma_rx_poison_buf(dma_dev, slot);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* Unmap buffer to make it accessible to the CPU */
|
||||
+ dma_unmap_single(dma_dev, dma_addr,
|
||||
+ BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
+
|
||||
+ /* Get info from the header */
|
||||
+ len = le16_to_cpu(rx->len);
|
||||
+ flags = le16_to_cpu(rx->flags);
|
||||
|
||||
/* Check for poison and drop or pass the packet */
|
||||
if (len == 0xdead && flags == 0xbeef) {
|
||||
bgmac_err(bgmac, "Found poisoned packet at slot %d, DMA issue!\n",
|
||||
ring->start);
|
||||
- dma_sync_single_for_device(dma_dev,
|
||||
- slot->dma_addr,
|
||||
- BGMAC_RX_BUF_SIZE,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ put_page(virt_to_head_page(buf));
|
||||
break;
|
||||
}
|
||||
|
||||
/* Omit CRC. */
|
||||
len -= ETH_FCS_LEN;
|
||||
|
||||
- /* Prepare new skb as replacement */
|
||||
- err = bgmac_dma_rx_skb_for_slot(bgmac, slot);
|
||||
- if (err) {
|
||||
- /* Poison the old skb */
|
||||
- rx->len = cpu_to_le16(0xdead);
|
||||
- rx->flags = cpu_to_le16(0xbeef);
|
||||
-
|
||||
- dma_sync_single_for_device(dma_dev,
|
||||
- slot->dma_addr,
|
||||
- BGMAC_RX_BUF_SIZE,
|
||||
- DMA_FROM_DEVICE);
|
||||
- break;
|
||||
- }
|
||||
- bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
|
||||
-
|
||||
- /* Unmap old skb, we'll pass it to the netfif */
|
||||
- dma_unmap_single(dma_dev, old_dma_addr,
|
||||
- BGMAC_RX_BUF_SIZE, DMA_FROM_DEVICE);
|
||||
-
|
||||
skb = build_skb(buf, BGMAC_RX_ALLOC_SIZE);
|
||||
skb_put(skb, BGMAC_RX_FRAME_OFFSET +
|
||||
BGMAC_RX_BUF_OFFSET + len);
|
||||
@@ -465,6 +460,8 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
handled++;
|
||||
} while (0);
|
||||
|
||||
+ bgmac_dma_rx_setup_desc(bgmac, ring, ring->start);
|
||||
+
|
||||
if (++ring->start >= BGMAC_RX_RING_SLOTS)
|
||||
ring->start = 0;
|
||||
|
||||
@@ -532,14 +529,14 @@ static void bgmac_dma_rx_ring_free(struc
|
||||
|
||||
for (i = 0; i < ring->num_slots; i++) {
|
||||
slot = &ring->slots[i];
|
||||
- if (!slot->buf)
|
||||
+ if (!slot->dma_addr)
|
||||
continue;
|
||||
|
||||
- if (slot->dma_addr)
|
||||
- dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
- BGMAC_RX_BUF_SIZE,
|
||||
- DMA_FROM_DEVICE);
|
||||
+ dma_unmap_single(dma_dev, slot->dma_addr,
|
||||
+ BGMAC_RX_BUF_SIZE,
|
||||
+ DMA_FROM_DEVICE);
|
||||
put_page(virt_to_head_page(slot->buf));
|
||||
+ slot->dma_addr = 0;
|
||||
}
|
||||
}
|
||||
|
@ -1,27 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 22:28:20 +0200
|
||||
Subject: [PATCH] bgmac: add check for oversized packets
|
||||
|
||||
In very rare cases, the MAC can catch an internal buffer that is bigger
|
||||
than it's supposed to be. Instead of crashing the kernel, simply pass
|
||||
the buffer back to the hardware
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -445,6 +445,13 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
break;
|
||||
}
|
||||
|
||||
+ if (len > BGMAC_RX_ALLOC_SIZE) {
|
||||
+ bgmac_err(bgmac, "Found oversized packet at slot %d, DMA issue!\n",
|
||||
+ ring->start);
|
||||
+ put_page(virt_to_head_page(buf));
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
/* Omit CRC. */
|
||||
len -= ETH_FCS_LEN;
|
||||
|
@ -1,23 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 22:36:16 +0200
|
||||
Subject: [PATCH] bgmac: increase rx ring size from 511 to 512
|
||||
|
||||
Limiting it to 511 looks like a failed attempt at leaving one descriptor
|
||||
empty to allow the hardware to stop processing a buffer that has not
|
||||
been prepared yet. However, this doesn't work because this affects the
|
||||
total ring size as well
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -356,7 +356,7 @@
|
||||
#define BGMAC_MAX_RX_RINGS 1
|
||||
|
||||
#define BGMAC_TX_RING_SLOTS 128
|
||||
-#define BGMAC_RX_RING_SLOTS 512 - 1 /* Why -1? Well, Broadcom does that... */
|
||||
+#define BGMAC_RX_RING_SLOTS 512
|
||||
|
||||
#define BGMAC_RX_HEADER_LEN 28 /* Last 24 bytes are unused. Well... */
|
||||
#define BGMAC_RX_FRAME_OFFSET 30 /* There are 2 unused bytes between header and real data */
|
@ -1,184 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 23:19:32 +0200
|
||||
Subject: [PATCH] bgmac: simplify dma init/cleanup
|
||||
|
||||
Instead of allocating buffers at device init time and initializing
|
||||
descriptors at device open, do both at the same time (during open).
|
||||
Free all buffers when closing the device.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -562,18 +562,26 @@ static void bgmac_dma_ring_desc_free(str
|
||||
ring->dma_base);
|
||||
}
|
||||
|
||||
-static void bgmac_dma_free(struct bgmac *bgmac)
|
||||
+static void bgmac_dma_cleanup(struct bgmac *bgmac)
|
||||
{
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
||||
bgmac_dma_tx_ring_free(bgmac, &bgmac->tx_ring[i]);
|
||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
||||
- }
|
||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
||||
+
|
||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
||||
bgmac_dma_rx_ring_free(bgmac, &bgmac->rx_ring[i]);
|
||||
+}
|
||||
+
|
||||
+static void bgmac_dma_free(struct bgmac *bgmac)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
||||
+
|
||||
+ for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
||||
bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
||||
- }
|
||||
}
|
||||
|
||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
||||
@@ -621,8 +629,6 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
}
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
||||
- int j;
|
||||
-
|
||||
ring = &bgmac->rx_ring[i];
|
||||
ring->num_slots = BGMAC_RX_RING_SLOTS;
|
||||
ring->mmio_base = ring_base[i];
|
||||
@@ -645,15 +651,6 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
ring->index_base = lower_32_bits(ring->dma_base);
|
||||
else
|
||||
ring->index_base = 0;
|
||||
-
|
||||
- /* Alloc RX slots */
|
||||
- for (j = 0; j < ring->num_slots; j++) {
|
||||
- err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
||||
- if (err) {
|
||||
- bgmac_err(bgmac, "Can't allocate skb for slot in RX ring\n");
|
||||
- goto err_dma_free;
|
||||
- }
|
||||
- }
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -663,10 +660,10 @@ err_dma_free:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
-static void bgmac_dma_init(struct bgmac *bgmac)
|
||||
+static int bgmac_dma_init(struct bgmac *bgmac)
|
||||
{
|
||||
struct bgmac_dma_ring *ring;
|
||||
- int i;
|
||||
+ int i, err;
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
||||
ring = &bgmac->tx_ring[i];
|
||||
@@ -698,8 +695,13 @@ static void bgmac_dma_init(struct bgmac
|
||||
if (ring->unaligned)
|
||||
bgmac_dma_rx_enable(bgmac, ring);
|
||||
|
||||
- for (j = 0; j < ring->num_slots; j++)
|
||||
+ for (j = 0; j < ring->num_slots; j++) {
|
||||
+ err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
||||
+ if (err)
|
||||
+ goto error;
|
||||
+
|
||||
bgmac_dma_rx_setup_desc(bgmac, ring, j);
|
||||
+ }
|
||||
|
||||
bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
||||
ring->index_base +
|
||||
@@ -708,6 +710,12 @@ static void bgmac_dma_init(struct bgmac
|
||||
ring->start = 0;
|
||||
ring->end = 0;
|
||||
}
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+error:
|
||||
+ bgmac_dma_cleanup(bgmac);
|
||||
+ return err;
|
||||
}
|
||||
|
||||
/**************************************************
|
||||
@@ -1183,11 +1191,8 @@ static void bgmac_enable(struct bgmac *b
|
||||
}
|
||||
|
||||
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipinit */
|
||||
-static void bgmac_chip_init(struct bgmac *bgmac, bool full_init)
|
||||
+static void bgmac_chip_init(struct bgmac *bgmac)
|
||||
{
|
||||
- struct bgmac_dma_ring *ring;
|
||||
- int i;
|
||||
-
|
||||
/* 1 interrupt per received frame */
|
||||
bgmac_write(bgmac, BGMAC_INT_RECV_LAZY, 1 << BGMAC_IRL_FC_SHIFT);
|
||||
|
||||
@@ -1205,16 +1210,7 @@ static void bgmac_chip_init(struct bgmac
|
||||
|
||||
bgmac_write(bgmac, BGMAC_RXMAX_LENGTH, 32 + ETHER_MAX_LEN);
|
||||
|
||||
- if (full_init) {
|
||||
- bgmac_dma_init(bgmac);
|
||||
- if (1) /* FIXME: is there any case we don't want IRQs? */
|
||||
- bgmac_chip_intrs_on(bgmac);
|
||||
- } else {
|
||||
- for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
||||
- ring = &bgmac->rx_ring[i];
|
||||
- bgmac_dma_rx_enable(bgmac, ring);
|
||||
- }
|
||||
- }
|
||||
+ bgmac_chip_intrs_on(bgmac);
|
||||
|
||||
bgmac_enable(bgmac);
|
||||
}
|
||||
@@ -1274,23 +1270,27 @@ static int bgmac_open(struct net_device
|
||||
int err = 0;
|
||||
|
||||
bgmac_chip_reset(bgmac);
|
||||
+
|
||||
+ err = bgmac_dma_init(bgmac);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
/* Specs say about reclaiming rings here, but we do that in DMA init */
|
||||
- bgmac_chip_init(bgmac, true);
|
||||
+ bgmac_chip_init(bgmac);
|
||||
|
||||
err = request_irq(bgmac->core->irq, bgmac_interrupt, IRQF_SHARED,
|
||||
KBUILD_MODNAME, net_dev);
|
||||
if (err < 0) {
|
||||
bgmac_err(bgmac, "IRQ request error: %d!\n", err);
|
||||
- goto err_out;
|
||||
+ bgmac_dma_cleanup(bgmac);
|
||||
+ return err;
|
||||
}
|
||||
napi_enable(&bgmac->napi);
|
||||
|
||||
phy_start(bgmac->phy_dev);
|
||||
|
||||
netif_carrier_on(net_dev);
|
||||
-
|
||||
-err_out:
|
||||
- return err;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int bgmac_stop(struct net_device *net_dev)
|
||||
@@ -1306,6 +1306,7 @@ static int bgmac_stop(struct net_device
|
||||
free_irq(bgmac->core->irq, net_dev);
|
||||
|
||||
bgmac_chip_reset(bgmac);
|
||||
+ bgmac_dma_cleanup(bgmac);
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,88 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 11:59:47 +0200
|
||||
Subject: [PATCH] bgmac: fix DMA rx corruption
|
||||
|
||||
The driver needs to inform the hardware about the first invalid (not yet
|
||||
filled) rx slot, by writing its DMA descriptor pointer offset to the
|
||||
BGMAC_DMA_RX_INDEX register.
|
||||
|
||||
This register was set to a value exceeding the rx ring size, effectively
|
||||
allowing the hardware constant access to the full ring, regardless of
|
||||
which slots are initialized.
|
||||
|
||||
To fix this issue, always mark the last filled rx slot as invalid.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -366,6 +366,16 @@ static int bgmac_dma_rx_skb_for_slot(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void bgmac_dma_rx_update_index(struct bgmac *bgmac,
|
||||
+ struct bgmac_dma_ring *ring)
|
||||
+{
|
||||
+ wmb();
|
||||
+
|
||||
+ bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
||||
+ ring->index_base +
|
||||
+ ring->end * sizeof(struct bgmac_dma_desc));
|
||||
+}
|
||||
+
|
||||
static void bgmac_dma_rx_setup_desc(struct bgmac *bgmac,
|
||||
struct bgmac_dma_ring *ring, int desc_idx)
|
||||
{
|
||||
@@ -384,6 +394,8 @@ static void bgmac_dma_rx_setup_desc(stru
|
||||
dma_desc->addr_high = cpu_to_le32(upper_32_bits(ring->slots[desc_idx].dma_addr));
|
||||
dma_desc->ctl0 = cpu_to_le32(ctl0);
|
||||
dma_desc->ctl1 = cpu_to_le32(ctl1);
|
||||
+
|
||||
+ ring->end = desc_idx;
|
||||
}
|
||||
|
||||
static void bgmac_dma_rx_poison_buf(struct device *dma_dev,
|
||||
@@ -411,9 +423,7 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
end_slot &= BGMAC_DMA_RX_STATDPTR;
|
||||
end_slot /= sizeof(struct bgmac_dma_desc);
|
||||
|
||||
- ring->end = end_slot;
|
||||
-
|
||||
- while (ring->start != ring->end) {
|
||||
+ while (ring->start != end_slot) {
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
struct bgmac_slot_info *slot = &ring->slots[ring->start];
|
||||
struct bgmac_rx_header *rx = slot->buf + BGMAC_RX_BUF_OFFSET;
|
||||
@@ -476,6 +486,8 @@ static int bgmac_dma_rx_read(struct bgma
|
||||
break;
|
||||
}
|
||||
|
||||
+ bgmac_dma_rx_update_index(bgmac, ring);
|
||||
+
|
||||
return handled;
|
||||
}
|
||||
|
||||
@@ -695,6 +707,8 @@ static int bgmac_dma_init(struct bgmac *
|
||||
if (ring->unaligned)
|
||||
bgmac_dma_rx_enable(bgmac, ring);
|
||||
|
||||
+ ring->start = 0;
|
||||
+ ring->end = 0;
|
||||
for (j = 0; j < ring->num_slots; j++) {
|
||||
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
||||
if (err)
|
||||
@@ -703,12 +717,7 @@ static int bgmac_dma_init(struct bgmac *
|
||||
bgmac_dma_rx_setup_desc(bgmac, ring, j);
|
||||
}
|
||||
|
||||
- bgmac_write(bgmac, ring->mmio_base + BGMAC_DMA_RX_INDEX,
|
||||
- ring->index_base +
|
||||
- ring->num_slots * sizeof(struct bgmac_dma_desc));
|
||||
-
|
||||
- ring->start = 0;
|
||||
- ring->end = 0;
|
||||
+ bgmac_dma_rx_update_index(bgmac, ring);
|
||||
}
|
||||
|
||||
return 0;
|
@ -1,132 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 12 Apr 2015 23:28:38 +0200
|
||||
Subject: [PATCH] bgmac: drop ring->num_slots
|
||||
|
||||
The ring size is always known at compile time, so make the code a bit
|
||||
more efficient
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -123,7 +123,7 @@ bgmac_dma_tx_add_buf(struct bgmac *bgmac
|
||||
struct bgmac_dma_desc *dma_desc;
|
||||
u32 ctl1;
|
||||
|
||||
- if (i == ring->num_slots - 1)
|
||||
+ if (i == BGMAC_TX_RING_SLOTS - 1)
|
||||
ctl0 |= BGMAC_DESC_CTL0_EOT;
|
||||
|
||||
ctl1 = len & BGMAC_DESC_CTL1_LEN;
|
||||
@@ -382,7 +382,7 @@ static void bgmac_dma_rx_setup_desc(stru
|
||||
struct bgmac_dma_desc *dma_desc = ring->cpu_base + desc_idx;
|
||||
u32 ctl0 = 0, ctl1 = 0;
|
||||
|
||||
- if (desc_idx == ring->num_slots - 1)
|
||||
+ if (desc_idx == BGMAC_RX_RING_SLOTS - 1)
|
||||
ctl0 |= BGMAC_DESC_CTL0_EOT;
|
||||
ctl1 |= BGMAC_RX_BUF_SIZE & BGMAC_DESC_CTL1_LEN;
|
||||
/* Is there any BGMAC device that requires extension? */
|
||||
@@ -521,7 +521,7 @@ static void bgmac_dma_tx_ring_free(struc
|
||||
struct bgmac_slot_info *slot;
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < ring->num_slots; i++) {
|
||||
+ for (i = 0; i < BGMAC_TX_RING_SLOTS; i++) {
|
||||
int len = dma_desc[i].ctl1 & BGMAC_DESC_CTL1_LEN;
|
||||
|
||||
slot = &ring->slots[i];
|
||||
@@ -546,7 +546,7 @@ static void bgmac_dma_rx_ring_free(struc
|
||||
struct bgmac_slot_info *slot;
|
||||
int i;
|
||||
|
||||
- for (i = 0; i < ring->num_slots; i++) {
|
||||
+ for (i = 0; i < BGMAC_RX_RING_SLOTS; i++) {
|
||||
slot = &ring->slots[i];
|
||||
if (!slot->dma_addr)
|
||||
continue;
|
||||
@@ -560,7 +560,8 @@ static void bgmac_dma_rx_ring_free(struc
|
||||
}
|
||||
|
||||
static void bgmac_dma_ring_desc_free(struct bgmac *bgmac,
|
||||
- struct bgmac_dma_ring *ring)
|
||||
+ struct bgmac_dma_ring *ring,
|
||||
+ int num_slots)
|
||||
{
|
||||
struct device *dma_dev = bgmac->core->dma_dev;
|
||||
int size;
|
||||
@@ -569,7 +570,7 @@ static void bgmac_dma_ring_desc_free(str
|
||||
return;
|
||||
|
||||
/* Free ring of descriptors */
|
||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
||||
+ size = num_slots * sizeof(struct bgmac_dma_desc);
|
||||
dma_free_coherent(dma_dev, size, ring->cpu_base,
|
||||
ring->dma_base);
|
||||
}
|
||||
@@ -590,10 +591,12 @@ static void bgmac_dma_free(struct bgmac
|
||||
int i;
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++)
|
||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i]);
|
||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->tx_ring[i],
|
||||
+ BGMAC_TX_RING_SLOTS);
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++)
|
||||
- bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i]);
|
||||
+ bgmac_dma_ring_desc_free(bgmac, &bgmac->rx_ring[i],
|
||||
+ BGMAC_RX_RING_SLOTS);
|
||||
}
|
||||
|
||||
static int bgmac_dma_alloc(struct bgmac *bgmac)
|
||||
@@ -616,11 +619,10 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_TX_RINGS; i++) {
|
||||
ring = &bgmac->tx_ring[i];
|
||||
- ring->num_slots = BGMAC_TX_RING_SLOTS;
|
||||
ring->mmio_base = ring_base[i];
|
||||
|
||||
/* Alloc ring of descriptors */
|
||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
||||
+ size = BGMAC_TX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
|
||||
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
|
||||
&ring->dma_base,
|
||||
GFP_KERNEL);
|
||||
@@ -642,11 +644,10 @@ static int bgmac_dma_alloc(struct bgmac
|
||||
|
||||
for (i = 0; i < BGMAC_MAX_RX_RINGS; i++) {
|
||||
ring = &bgmac->rx_ring[i];
|
||||
- ring->num_slots = BGMAC_RX_RING_SLOTS;
|
||||
ring->mmio_base = ring_base[i];
|
||||
|
||||
/* Alloc ring of descriptors */
|
||||
- size = ring->num_slots * sizeof(struct bgmac_dma_desc);
|
||||
+ size = BGMAC_RX_RING_SLOTS * sizeof(struct bgmac_dma_desc);
|
||||
ring->cpu_base = dma_zalloc_coherent(dma_dev, size,
|
||||
&ring->dma_base,
|
||||
GFP_KERNEL);
|
||||
@@ -709,7 +710,7 @@ static int bgmac_dma_init(struct bgmac *
|
||||
|
||||
ring->start = 0;
|
||||
ring->end = 0;
|
||||
- for (j = 0; j < ring->num_slots; j++) {
|
||||
+ for (j = 0; j < BGMAC_RX_RING_SLOTS; j++) {
|
||||
err = bgmac_dma_rx_skb_for_slot(bgmac, &ring->slots[j]);
|
||||
if (err)
|
||||
goto error;
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -419,11 +419,10 @@ struct bgmac_dma_ring {
|
||||
u32 start;
|
||||
u32 end;
|
||||
|
||||
- u16 num_slots;
|
||||
- u16 mmio_base;
|
||||
struct bgmac_dma_desc *cpu_base;
|
||||
dma_addr_t dma_base;
|
||||
u32 index_base; /* Used for unaligned rings only, otherwise 0 */
|
||||
+ u16 mmio_base;
|
||||
bool unaligned;
|
||||
|
||||
struct bgmac_slot_info slots[BGMAC_RX_RING_SLOTS];
|
@ -1,24 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 13 Apr 2015 15:54:04 +0200
|
||||
Subject: [PATCH] bgmac: fix MAC soft-reset bit for corerev > 4
|
||||
|
||||
Only core revisions older than 4 use BGMAC_CMDCFG_SR_REV0
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -198,9 +198,9 @@
|
||||
#define BGMAC_CMDCFG_TAI 0x00000200
|
||||
#define BGMAC_CMDCFG_HD 0x00000400 /* Set if in half duplex mode */
|
||||
#define BGMAC_CMDCFG_HD_SHIFT 10
|
||||
-#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for other revs */
|
||||
-#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, only for core rev 4 */
|
||||
-#define BGMAC_CMDCFG_SR(rev) ((rev == 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
||||
+#define BGMAC_CMDCFG_SR_REV0 0x00000800 /* Set to reset mode, for core rev 0-3 */
|
||||
+#define BGMAC_CMDCFG_SR_REV4 0x00002000 /* Set to reset mode, for core rev >= 4 */
|
||||
+#define BGMAC_CMDCFG_SR(rev) ((rev >= 4) ? BGMAC_CMDCFG_SR_REV4 : BGMAC_CMDCFG_SR_REV0)
|
||||
#define BGMAC_CMDCFG_ML 0x00008000 /* Set to activate mac loopback mode */
|
||||
#define BGMAC_CMDCFG_AE 0x00400000
|
||||
#define BGMAC_CMDCFG_CFE 0x00800000
|
@ -1,28 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Mon, 13 Apr 2015 15:56:26 +0200
|
||||
Subject: [PATCH] bgmac: reset all 4 GMAC cores on init
|
||||
|
||||
On a BCM4709 based device, I found that GMAC cores may be enabled at
|
||||
probe time, but only become usable after a full reset.
|
||||
Disable cores before re-enabling them to ensure that they are properly
|
||||
reset.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1623,8 +1623,11 @@ static int bgmac_probe(struct bcma_devic
|
||||
ns_core = bcma_find_core_unit(core->bus,
|
||||
BCMA_CORE_MAC_GBIT,
|
||||
ns_gmac);
|
||||
- if (ns_core && !bcma_core_is_enabled(ns_core))
|
||||
- bcma_core_enable(ns_core, 0);
|
||||
+ if (!ns_core)
|
||||
+ continue;
|
||||
+
|
||||
+ bcma_core_disable(ns_core, 0);
|
||||
+ bcma_core_enable(ns_core, 0);
|
||||
}
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
From 047f89922c6381432501f248d08226ff9adc4ee3 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Thu, 23 Apr 2015 20:45:25 +0200
|
||||
Subject: [PATCH][FIX 4.1] bgmac: fix requests for extra polling calls from
|
||||
NAPI
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
After d75b1ade567f ("net: less interrupt masking in NAPI") polling
|
||||
function has to return whole budget when it wants NAPI to call it again.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
Cc: Felix Fietkau <nbd@openwrt.org>
|
||||
Fixes: eb64e2923a886 ("bgmac: leave interrupts disabled as long as there is work to do")
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -1260,7 +1260,7 @@ static int bgmac_poll(struct napi_struct
|
||||
|
||||
/* Poll again if more events arrived in the meantime */
|
||||
if (bgmac_read(bgmac, BGMAC_INT_STATUS) & (BGMAC_IS_TX0 | BGMAC_IS_RX))
|
||||
- return handled;
|
||||
+ return weight;
|
||||
|
||||
if (handled < weight) {
|
||||
napi_complete(napi);
|
@ -1,89 +0,0 @@
|
||||
From: Simon Farnsworth <simon@farnz.org.uk>
|
||||
Date: Sun, 1 Mar 2015 10:54:39 +0000
|
||||
Subject: [PATCH] pppoe: Use workqueue to die properly when a PADT is received
|
||||
|
||||
When a PADT frame is received, the socket may not be in a good state to
|
||||
close down the PPP interface. The current implementation handles this by
|
||||
simply blocking all further PPP traffic, and hoping that the lack of traffic
|
||||
will trigger the user to investigate.
|
||||
|
||||
Use schedule_work to get to a process context from which we clear down the
|
||||
PPP interface, in a fashion analogous to hangup on a TTY-based PPP
|
||||
interface. This causes pppd to disconnect immediately, and allows tools to
|
||||
take immediate corrective action.
|
||||
|
||||
Note that pppd's rp_pppoe.so plugin has code in it to disable the session
|
||||
when it disconnects; however, as a consequence of this patch, the session is
|
||||
already disabled before rp_pppoe.so is asked to disable the session. The
|
||||
result is a harmless error message:
|
||||
|
||||
Failed to disconnect PPPoE socket: 114 Operation already in progress
|
||||
|
||||
This message is safe to ignore, as long as the error is 114 Operation
|
||||
already in progress; in that specific case, it means that the PPPoE session
|
||||
has already been disabled before pppd tried to disable it.
|
||||
|
||||
Signed-off-by: Simon Farnsworth <simon@farnz.org.uk>
|
||||
Tested-by: Dan Williams <dcbw@redhat.com>
|
||||
Tested-by: Christoph Schulz <develop@kristov.de>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ppp/pppoe.c
|
||||
+++ b/drivers/net/ppp/pppoe.c
|
||||
@@ -455,6 +455,18 @@ out:
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
+static void pppoe_unbind_sock_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct pppox_sock *po = container_of(work, struct pppox_sock,
|
||||
+ proto.pppoe.padt_work);
|
||||
+ struct sock *sk = sk_pppox(po);
|
||||
+
|
||||
+ lock_sock(sk);
|
||||
+ pppox_unbind_sock(sk);
|
||||
+ release_sock(sk);
|
||||
+ sock_put(sk);
|
||||
+}
|
||||
+
|
||||
/************************************************************************
|
||||
*
|
||||
* Receive a PPPoE Discovery frame.
|
||||
@@ -500,7 +512,8 @@ static int pppoe_disc_rcv(struct sk_buff
|
||||
}
|
||||
|
||||
bh_unlock_sock(sk);
|
||||
- sock_put(sk);
|
||||
+ if (!schedule_work(&po->proto.pppoe.padt_work))
|
||||
+ sock_put(sk);
|
||||
}
|
||||
|
||||
abort:
|
||||
@@ -613,6 +626,8 @@ static int pppoe_connect(struct socket *
|
||||
|
||||
lock_sock(sk);
|
||||
|
||||
+ INIT_WORK(&po->proto.pppoe.padt_work, pppoe_unbind_sock_work);
|
||||
+
|
||||
error = -EINVAL;
|
||||
if (sp->sa_protocol != PX_PROTO_OE)
|
||||
goto end;
|
||||
--- a/include/linux/if_pppox.h
|
||||
+++ b/include/linux/if_pppox.h
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/ppp_channel.h>
|
||||
#include <linux/skbuff.h>
|
||||
+#include <linux/workqueue.h>
|
||||
#include <uapi/linux/if_pppox.h>
|
||||
|
||||
static inline struct pppoe_hdr *pppoe_hdr(const struct sk_buff *skb)
|
||||
@@ -32,6 +33,7 @@ struct pppoe_opt {
|
||||
struct pppoe_addr pa; /* what this socket is bound to*/
|
||||
struct sockaddr_pppox relay; /* what socket data will be
|
||||
relayed to (PPPoE relaying) */
|
||||
+ struct work_struct padt_work;/* Work item for handling PADT */
|
||||
};
|
||||
|
||||
struct pptp_opt {
|
@ -1,10 +0,0 @@
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -598,6 +598,7 @@ static const struct spi_device_id spi_no
|
||||
{ "s25fl016k", INFO(0xef4015, 0, 64 * 1024, 32, SECT_4K) },
|
||||
{ "s25fl064k", INFO(0xef4017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "s25fl132k", INFO(0x014016, 0, 64 * 1024, 64, 0) },
|
||||
+ { "s25fl164k", INFO(0x014017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
|
||||
/* SST -- large erase sizes are "overlays", "sectors" are 4K */
|
||||
{ "sst25vf040b", INFO(0xbf258d, 0, 64 * 1024, 8, SECT_4K | SST_WRITE) },
|
@ -1,146 +0,0 @@
|
||||
From 279c6c7fa64f5763e6b9f05e7ab3840092e702e7 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Date: Mon, 29 Jun 2015 14:57:48 -1000
|
||||
Subject: [PATCH] api: fix compatibility of linux/in.h with netinet/in.h
|
||||
|
||||
u
|
||||
This fixes breakage to iproute2 build with recent kernel headers
|
||||
caused by:
|
||||
commit a263653ed798216c0069922d7b5237ca49436007
|
||||
Author: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Wed Jun 17 10:28:27 2015 -0500
|
||||
|
||||
netfilter: don't pull include/linux/netfilter.h from netns headers
|
||||
|
||||
The issue is that definitions in linux/in.h overlap with those
|
||||
in netinet/in.h. This patch solves this by introducing the same
|
||||
mechanism as was used to solve the same problem with linux/in6.h
|
||||
|
||||
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
include/uapi/linux/in.h | 16 +++++++++++++---
|
||||
include/uapi/linux/libc-compat.h | 22 ++++++++++++++++++++++
|
||||
2 files changed, 35 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/uapi/linux/in.h
|
||||
+++ b/include/uapi/linux/in.h
|
||||
@@ -19,8 +19,10 @@
|
||||
#define _UAPI_LINUX_IN_H
|
||||
|
||||
#include <linux/types.h>
|
||||
+#include <linux/libc-compat.h>
|
||||
#include <linux/socket.h>
|
||||
|
||||
+#if __UAPI_DEF_IN_IPPROTO
|
||||
/* Standard well-defined IP protocols. */
|
||||
enum {
|
||||
IPPROTO_IP = 0, /* Dummy protocol for TCP */
|
||||
@@ -73,12 +75,14 @@ enum {
|
||||
#define IPPROTO_RAW IPPROTO_RAW
|
||||
IPPROTO_MAX
|
||||
};
|
||||
+#endif
|
||||
|
||||
-
|
||||
+#if __UAPI_DEF_IN_ADDR
|
||||
/* Internet address. */
|
||||
struct in_addr {
|
||||
__be32 s_addr;
|
||||
};
|
||||
+#endif
|
||||
|
||||
#define IP_TOS 1
|
||||
#define IP_TTL 2
|
||||
@@ -155,6 +159,7 @@ struct in_addr {
|
||||
|
||||
/* Request struct for multicast socket ops */
|
||||
|
||||
+#if __UAPI_DEF_IP_MREQ
|
||||
struct ip_mreq {
|
||||
struct in_addr imr_multiaddr; /* IP multicast address of group */
|
||||
struct in_addr imr_interface; /* local IP address of interface */
|
||||
@@ -206,14 +211,18 @@ struct group_filter {
|
||||
#define GROUP_FILTER_SIZE(numsrc) \
|
||||
(sizeof(struct group_filter) - sizeof(struct __kernel_sockaddr_storage) \
|
||||
+ (numsrc) * sizeof(struct __kernel_sockaddr_storage))
|
||||
+#endif
|
||||
|
||||
+#if __UAPI_DEF_IN_PKTINFO
|
||||
struct in_pktinfo {
|
||||
int ipi_ifindex;
|
||||
struct in_addr ipi_spec_dst;
|
||||
struct in_addr ipi_addr;
|
||||
};
|
||||
+#endif
|
||||
|
||||
/* Structure describing an Internet (IP) socket address. */
|
||||
+#if __UAPI_DEF_SOCKADDR_IN
|
||||
#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */
|
||||
struct sockaddr_in {
|
||||
__kernel_sa_family_t sin_family; /* Address family */
|
||||
@@ -225,8 +234,9 @@ struct sockaddr_in {
|
||||
sizeof(unsigned short int) - sizeof(struct in_addr)];
|
||||
};
|
||||
#define sin_zero __pad /* for BSD UNIX comp. -FvK */
|
||||
+#endif
|
||||
|
||||
-
|
||||
+#if __UAPI_DEF_IN_CLASS
|
||||
/*
|
||||
* Definitions of the bits in an Internet address integer.
|
||||
* On subnets, host and network parts are found according
|
||||
@@ -277,7 +287,7 @@ struct sockaddr_in {
|
||||
#define INADDR_ALLHOSTS_GROUP 0xe0000001U /* 224.0.0.1 */
|
||||
#define INADDR_ALLRTRS_GROUP 0xe0000002U /* 224.0.0.2 */
|
||||
#define INADDR_MAX_LOCAL_GROUP 0xe00000ffU /* 224.0.0.255 */
|
||||
-
|
||||
+#endif
|
||||
|
||||
/* <asm/byteorder.h> contains the htonl type stuff.. */
|
||||
#include <asm/byteorder.h>
|
||||
--- a/include/uapi/linux/libc-compat.h
|
||||
+++ b/include/uapi/linux/libc-compat.h
|
||||
@@ -56,6 +56,13 @@
|
||||
|
||||
/* GLIBC headers included first so don't define anything
|
||||
* that would already be defined. */
|
||||
+#define __UAPI_DEF_IN_ADDR 0
|
||||
+#define __UAPI_DEF_IN_IPPROTO 0
|
||||
+#define __UAPI_DEF_IN_PKTINFO 0
|
||||
+#define __UAPI_DEF_IP_MREQ 0
|
||||
+#define __UAPI_DEF_SOCKADDR_IN 0
|
||||
+#define __UAPI_DEF_IN_CLASS 0
|
||||
+
|
||||
#define __UAPI_DEF_IN6_ADDR 0
|
||||
/* The exception is the in6_addr macros which must be defined
|
||||
* if the glibc code didn't define them. This guard matches
|
||||
@@ -78,6 +85,13 @@
|
||||
/* Linux headers included first, and we must define everything
|
||||
* we need. The expectation is that glibc will check the
|
||||
* __UAPI_DEF_* defines and adjust appropriately. */
|
||||
+#define __UAPI_DEF_IN_ADDR 1
|
||||
+#define __UAPI_DEF_IN_IPPROTO 1
|
||||
+#define __UAPI_DEF_IN_PKTINFO 1
|
||||
+#define __UAPI_DEF_IP_MREQ 1
|
||||
+#define __UAPI_DEF_SOCKADDR_IN 1
|
||||
+#define __UAPI_DEF_IN_CLASS 1
|
||||
+
|
||||
#define __UAPI_DEF_IN6_ADDR 1
|
||||
/* We unconditionally define the in6_addr macros and glibc must
|
||||
* coordinate. */
|
||||
@@ -103,6 +117,14 @@
|
||||
* that we need. */
|
||||
#else /* !defined(__GLIBC__) */
|
||||
|
||||
+/* Definitions for in.h */
|
||||
+#define __UAPI_DEF_IN_ADDR 1
|
||||
+#define __UAPI_DEF_IN_IPPROTO 1
|
||||
+#define __UAPI_DEF_IN_PKTINFO 1
|
||||
+#define __UAPI_DEF_IP_MREQ 1
|
||||
+#define __UAPI_DEF_SOCKADDR_IN 1
|
||||
+#define __UAPI_DEF_IN_CLASS 1
|
||||
+
|
||||
/* Definitions for in6.h */
|
||||
#define __UAPI_DEF_IN6_ADDR 1
|
||||
#define __UAPI_DEF_IN6_ADDR_ALT 1
|
@ -1,27 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 9 May 2015 23:03:47 +0200
|
||||
Subject: [PATCH] pppoe: drop pppoe device in pppoe_unbind_sock_work
|
||||
|
||||
After receiving a PADT and the socket is closed, user space will no
|
||||
longer drop the reference to the pppoe device.
|
||||
This leads to errors like this:
|
||||
|
||||
[ 488.570000] unregister_netdevice: waiting for eth0.2 to become free. Usage count = 2
|
||||
|
||||
Fixes: 287f3a943fe ("pppoe: Use workqueue to die properly when a PADT is received")
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ppp/pppoe.c
|
||||
+++ b/drivers/net/ppp/pppoe.c
|
||||
@@ -462,6 +462,10 @@ static void pppoe_unbind_sock_work(struc
|
||||
struct sock *sk = sk_pppox(po);
|
||||
|
||||
lock_sock(sk);
|
||||
+ if (po->pppoe_dev) {
|
||||
+ dev_put(po->pppoe_dev);
|
||||
+ po->pppoe_dev = NULL;
|
||||
+ }
|
||||
pppox_unbind_sock(sk);
|
||||
release_sock(sk);
|
||||
sock_put(sk);
|
@ -1,82 +0,0 @@
|
||||
From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <florian@openwrt.org>
|
||||
Date: Mon, 28 Jan 2013 20:06:29 +0100
|
||||
Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
|
||||
checking
|
||||
|
||||
This patch adds an ignore_oc flag which can be set by EHCI controller
|
||||
not supporting or wanting to disable overcurrent checking. The EHCI
|
||||
platform data in include/linux/usb/ehci_pdriver.h is also augmented to
|
||||
take advantage of this new flag.
|
||||
|
||||
Signed-off-by: Florian Fainelli <florian@openwrt.org>
|
||||
---
|
||||
drivers/usb/host/ehci-hcd.c | 2 +-
|
||||
drivers/usb/host/ehci-hub.c | 4 ++--
|
||||
drivers/usb/host/ehci-platform.c | 1 +
|
||||
drivers/usb/host/ehci.h | 1 +
|
||||
include/linux/usb/ehci_pdriver.h | 1 +
|
||||
5 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ehci-hcd.c
|
||||
+++ b/drivers/usb/host/ehci-hcd.c
|
||||
@@ -638,7 +638,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
|
||||
@@ -633,7 +633,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;
|
||||
@@ -995,7 +995,7 @@ int ehci_hub_control(
|
||||
if (temp & PORT_PEC)
|
||||
status |= USB_PORT_STAT_C_ENABLE << 16;
|
||||
|
||||
- if ((temp & PORT_OCC) && !ignore_oc){
|
||||
+ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
|
||||
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||
|
||||
/*
|
||||
--- a/drivers/usb/host/ehci-platform.c
|
||||
+++ b/drivers/usb/host/ehci-platform.c
|
||||
@@ -264,6 +264,8 @@ static int ehci_platform_probe(struct pl
|
||||
ehci->big_endian_desc = 1;
|
||||
if (pdata->big_endian_mmio)
|
||||
ehci->big_endian_mmio = 1;
|
||||
+ if (pdata->ignore_oc)
|
||||
+ ehci->ignore_oc = 1;
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
if (ehci->big_endian_mmio) {
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -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
|
||||
@@ -49,6 +49,7 @@ struct usb_ehci_pdata {
|
||||
unsigned no_io_watchdog:1;
|
||||
unsigned reset_on_resume:1;
|
||||
unsigned dma_mask_64:1;
|
||||
+ unsigned ignore_oc:1;
|
||||
|
||||
/* Turn on all power and clocks */
|
||||
int (*power_on)(struct platform_device *pdev);
|
@ -1,86 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Fri, 10 Apr 2015 13:35:29 +0200
|
||||
Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
|
||||
|
||||
It is required for renames on overlayfs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -35,7 +35,7 @@ static int jffs2_mkdir (struct inode *,s
|
||||
static int jffs2_rmdir (struct inode *,struct dentry *);
|
||||
static int jffs2_mknod (struct inode *,struct dentry *,umode_t,dev_t);
|
||||
static int jffs2_rename (struct inode *, struct dentry *,
|
||||
- struct inode *, struct dentry *);
|
||||
+ struct inode *, struct dentry *, unsigned int);
|
||||
|
||||
const struct file_operations jffs2_dir_operations =
|
||||
{
|
||||
@@ -57,7 +57,7 @@ const struct inode_operations jffs2_dir_
|
||||
.mkdir = jffs2_mkdir,
|
||||
.rmdir = jffs2_rmdir,
|
||||
.mknod = jffs2_mknod,
|
||||
- .rename = jffs2_rename,
|
||||
+ .rename2 = jffs2_rename,
|
||||
.get_acl = jffs2_get_acl,
|
||||
.set_acl = jffs2_set_acl,
|
||||
.setattr = jffs2_setattr,
|
||||
@@ -756,8 +756,27 @@ static int jffs2_mknod (struct inode *di
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int jffs2_whiteout(struct inode *old_dir, struct dentry *old_dentry)
|
||||
+{
|
||||
+ struct dentry *wh;
|
||||
+ int err;
|
||||
+
|
||||
+ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
|
||||
+ if (!wh)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
|
||||
+ WHITEOUT_DEV);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ d_rehash(wh);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
- struct inode *new_dir_i, struct dentry *new_dentry)
|
||||
+ struct inode *new_dir_i, struct dentry *new_dentry,
|
||||
+ unsigned int flags)
|
||||
{
|
||||
int ret;
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
|
||||
@@ -765,6 +784,9 @@ static int jffs2_rename (struct inode *o
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
+ if (flags & ~RENAME_WHITEOUT)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
* file over a directory and vice versa, but if it's a directory,
|
||||
* the VFS can't check whether the victim is empty. The filesystem
|
||||
@@ -828,9 +850,14 @@ static int jffs2_rename (struct inode *o
|
||||
if (d_is_dir(old_dentry) && !victim_f)
|
||||
inc_nlink(new_dir_i);
|
||||
|
||||
- /* Unlink the original */
|
||||
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
|
||||
+ if (flags & RENAME_WHITEOUT)
|
||||
+ /* Replace with whiteout */
|
||||
+ ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||
+ else
|
||||
+ /* Unlink the original */
|
||||
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
+ old_dentry->d_name.name,
|
||||
+ old_dentry->d_name.len, NULL, now);
|
||||
|
||||
/* We don't touch inode->i_nlink */
|
||||
|
@ -1,58 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sat, 25 Apr 2015 12:41:32 +0200
|
||||
Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
- if (flags & ~RENAME_WHITEOUT)
|
||||
+ if (flags & ~(RENAME_WHITEOUT | RENAME_EXCHANGE))
|
||||
return -EINVAL;
|
||||
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o
|
||||
* the VFS can't check whether the victim is empty. The filesystem
|
||||
* needs to do that for itself.
|
||||
*/
|
||||
- if (new_dentry->d_inode) {
|
||||
+ if (new_dentry->d_inode && !(flags & RENAME_EXCHANGE)) {
|
||||
victim_f = JFFS2_INODE_INFO(new_dentry->d_inode);
|
||||
if (d_is_dir(new_dentry)) {
|
||||
struct jffs2_full_dirent *fd;
|
||||
@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (victim_f) {
|
||||
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
|
||||
/* There was a victim. Kill it off nicely */
|
||||
if (d_is_dir(new_dentry))
|
||||
clear_nlink(new_dentry->d_inode);
|
||||
@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o
|
||||
if (flags & RENAME_WHITEOUT)
|
||||
/* Replace with whiteout */
|
||||
ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||
+ else if (flags & RENAME_EXCHANGE)
|
||||
+ /* Replace the original */
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
+ new_dentry->d_inode->i_ino, type,
|
||||
+ old_dentry->d_name.name, old_dentry->d_name.len,
|
||||
+ now);
|
||||
else
|
||||
/* Unlink the original */
|
||||
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
@@ -879,7 +885,7 @@ static int jffs2_rename (struct inode *o
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (d_is_dir(old_dentry))
|
||||
+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
|
||||
drop_nlink(old_dir_i);
|
||||
|
||||
new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
|
@ -1,54 +0,0 @@
|
||||
From: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Subject: bridge: allow receiption on disabled port
|
||||
|
||||
When an ethernet device is enslaved to a bridge, and the bridge STP
|
||||
detects loss of carrier (or operational state down), then normally
|
||||
packet receiption is blocked.
|
||||
|
||||
This breaks control applications like WPA which maybe expecting to
|
||||
receive packets to negotiate to bring link up. The bridge needs to
|
||||
block forwarding packets from these disabled ports, but there is no
|
||||
hard requirement to not allow local packet delivery.
|
||||
|
||||
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -207,11 +207,13 @@ EXPORT_SYMBOL_GPL(br_handle_frame_finish
|
||||
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 */
|
||||
}
|
||||
|
||||
@@ -285,6 +287,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) {
|
@ -1,35 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Date: Sun, 19 Jul 2015 00:21:57 +0200
|
||||
Subject: [PATCH] MIPS: kernel: fix sched_getaffinity with MT FPAFF enabled
|
||||
|
||||
p->thread.user_cpus_allowed is zero-initialized and is only filled on
|
||||
the first sched_setaffinity call.
|
||||
|
||||
To avoid adding overhead in the task initialization codepath, simply OR
|
||||
the returned mask in sched_getaffinity with p->cpus_allowed.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/arch/mips/kernel/mips-mt-fpaff.c
|
||||
+++ b/arch/mips/kernel/mips-mt-fpaff.c
|
||||
@@ -154,7 +154,7 @@ asmlinkage long mipsmt_sys_sched_getaffi
|
||||
unsigned long __user *user_mask_ptr)
|
||||
{
|
||||
unsigned int real_len;
|
||||
- cpumask_t mask;
|
||||
+ cpumask_t allowed, mask;
|
||||
int retval;
|
||||
struct task_struct *p;
|
||||
|
||||
@@ -173,7 +173,8 @@ asmlinkage long mipsmt_sys_sched_getaffi
|
||||
if (retval)
|
||||
goto out_unlock;
|
||||
|
||||
- cpumask_and(&mask, &p->thread.user_cpus_allowed, cpu_possible_mask);
|
||||
+ cpumask_or(&allowed, &p->thread.user_cpus_allowed, &p->cpus_allowed);
|
||||
+ cpumask_and(&mask, &allowed, cpu_active_mask);
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&tasklist_lock);
|
@ -1,693 +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
|
||||
@@ -1526,6 +1526,7 @@ config CPU_CAVIUM_OCTEON
|
||||
select CPU_SUPPORTS_HUGEPAGES
|
||||
select USB_EHCI_BIG_ENDIAN_MMIO
|
||||
select MIPS_L1_CACHE_SHIFT_7
|
||||
+ select SYS_HAS_DMA_OPS
|
||||
help
|
||||
The Cavium Octeon processor is a highly integrated chip containing
|
||||
many ethernet hardware widgets for networking tasks. The processor
|
||||
@@ -1790,6 +1791,9 @@ config MIPS_MALTA_PM
|
||||
bool
|
||||
default y
|
||||
|
||||
+config SYS_HAS_DMA_OPS
|
||||
+ bool
|
||||
+
|
||||
#
|
||||
# CPU may reorder R->R, R->W, W->R, W->W
|
||||
# Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
|
||||
--- a/arch/mips/include/asm/dma-mapping.h
|
||||
+++ b/arch/mips/include/asm/dma-mapping.h
|
||||
@@ -1,9 +1,16 @@
|
||||
#ifndef _ASM_DMA_MAPPING_H
|
||||
#define _ASM_DMA_MAPPING_H
|
||||
|
||||
+#include <linux/kmemcheck.h>
|
||||
+#include <linux/bug.h>
|
||||
+#include <linux/scatterlist.h>
|
||||
+#include <linux/dma-debug.h>
|
||||
+#include <linux/dma-attrs.h>
|
||||
+
|
||||
#include <asm/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,304 @@ 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)
|
||||
+
|
||||
+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 +378,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
|
||||
@@ -54,7 +391,7 @@ dma_set_mask(struct device *dev, u64 mas
|
||||
if(!dev->dma_mask || !dma_supported(dev, mask))
|
||||
return -EIO;
|
||||
|
||||
- if (ops->set_dma_mask)
|
||||
+ if (ops && ops->set_dma_mask)
|
||||
return ops->set_dma_mask(dev, mask);
|
||||
|
||||
*dev->dma_mask = mask;
|
||||
@@ -74,7 +411,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);
|
||||
|
||||
@@ -89,7 +430,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
|
||||
@@ -26,7 +26,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)
|
||||
@@ -46,35 +46,6 @@ static int __init setnocoherentio(char *
|
||||
early_param("nocoherentio", setnocoherentio);
|
||||
#endif
|
||||
|
||||
-static inline struct page *dma_addr_to_page(struct device *dev,
|
||||
- dma_addr_t dma_addr)
|
||||
-{
|
||||
- return pfn_to_page(
|
||||
- plat_dma_addr_to_phys(dev, dma_addr) >> PAGE_SHIFT);
|
||||
-}
|
||||
-
|
||||
-/*
|
||||
- * The affected CPUs below in 'cpu_needs_post_dma_flush()' can
|
||||
- * speculatively fill random cachelines with stale data at any time,
|
||||
- * requiring an extra flush post-DMA.
|
||||
- *
|
||||
- * Warning on the terminology - Linux calls an uncached area coherent;
|
||||
- * MIPS terminology calls memory areas with hardware maintained coherency
|
||||
- * coherent.
|
||||
- *
|
||||
- * Note that the R14000 and R16000 should also be checked for in this
|
||||
- * condition. However this function is only called on non-I/O-coherent
|
||||
- * systems and only the R10000 and R12000 are used in such systems, the
|
||||
- * SGI IP28 Indigo² rsp. SGI IP32 aka O2.
|
||||
- */
|
||||
-static inline int cpu_needs_post_dma_flush(struct device *dev)
|
||||
-{
|
||||
- return !plat_device_is_coherent(dev) &&
|
||||
- (boot_cpu_type() == CPU_R10000 ||
|
||||
- boot_cpu_type() == CPU_R12000 ||
|
||||
- boot_cpu_type() == CPU_BMIPS5000);
|
||||
-}
|
||||
-
|
||||
static gfp_t massage_gfp_flags(const struct device *dev, gfp_t gfp)
|
||||
{
|
||||
gfp_t dma_flag;
|
||||
@@ -130,8 +101,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;
|
||||
struct page *page = NULL;
|
||||
@@ -162,6 +134,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,
|
||||
@@ -172,8 +145,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);
|
||||
@@ -193,6 +166,7 @@ static void mips_dma_free_coherent(struc
|
||||
if (!dma_release_from_contiguous(dev, page, count))
|
||||
__free_pages(page, 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)
|
||||
@@ -221,8 +195,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;
|
||||
|
||||
@@ -251,108 +225,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)
|
||||
@@ -365,23 +238,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)
|
||||
|
@ -1,58 +0,0 @@
|
||||
From 71a0a72456b48de972d7ed613b06a22a3aa9057f Mon Sep 17 00:00:00 2001
|
||||
From: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Date: Sat, 26 Sep 2015 13:41:43 +0800
|
||||
Subject: [PATCH] MIPS: UAPI: Ignore __arch_swab{16,32,64} when using MIPS16
|
||||
|
||||
Some GCC versions (e.g. 4.8.3) can incorrectly inline a function with
|
||||
MIPS32 instructions into another function with MIPS16 code [1], causing
|
||||
the assembler to genereate incorrect binary code or fail right away
|
||||
complaining about unrecognized opcode.
|
||||
|
||||
In the case of __arch_swab{16,32}, when inlined by the compiler with
|
||||
flags `-mips32r2 -mips16 -Os', the assembler can fail with the following
|
||||
error.
|
||||
|
||||
{standard input}:79: Error: unrecognized opcode `wsbh $2,$2'
|
||||
|
||||
For performance concerns and to workaround the issue already existing in
|
||||
older compilers, just ignore these 2 functions when compiling with
|
||||
mips16 enabled.
|
||||
|
||||
[1] Inlining nomips16 function into mips16 function can result in
|
||||
undefined builtins, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=55777
|
||||
|
||||
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Cc: Maciej W. Rozycki <macro@linux-mips.org>
|
||||
Cc: linux-mips@linux-mips.org
|
||||
Patchwork: https://patchwork.linux-mips.org/patch/11241/
|
||||
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
|
||||
---
|
||||
arch/mips/include/uapi/asm/swab.h | 7 ++++---
|
||||
1 file changed, 4 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/arch/mips/include/uapi/asm/swab.h b/arch/mips/include/uapi/asm/swab.h
|
||||
index 8f2d184..23cd9b1 100644
|
||||
--- a/arch/mips/include/uapi/asm/swab.h
|
||||
+++ b/arch/mips/include/uapi/asm/swab.h
|
||||
@@ -13,8 +13,9 @@
|
||||
|
||||
#define __SWAB_64_THRU_32__
|
||||
|
||||
-#if (defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \
|
||||
- defined(_MIPS_ARCH_LOONGSON3A)
|
||||
+#if !defined(__mips16) && \
|
||||
+ ((defined(__mips_isa_rev) && (__mips_isa_rev >= 2)) || \
|
||||
+ defined(_MIPS_ARCH_LOONGSON3A))
|
||||
|
||||
static inline __attribute_const__ __u16 __arch_swab16(__u16 x)
|
||||
{
|
||||
@@ -65,5 +66,5 @@ static inline __attribute_const__ __u64 __arch_swab64(__u64 x)
|
||||
}
|
||||
#define __arch_swab64 __arch_swab64
|
||||
#endif /* __mips64 */
|
||||
-#endif /* MIPS R2 or newer or Loongson 3A */
|
||||
+#endif /* (not __mips16) and (MIPS R2 or newer or Loongson 3A) */
|
||||
#endif /* _ASM_SWAB_H */
|
||||
--
|
||||
1.7.10.4
|
||||
|
@ -1,148 +0,0 @@
|
||||
Patch by: Miklos Szeredi <miklos@szeredi.hu>
|
||||
|
||||
Some filesystems (e.g. jffs2) lock the same resources for both readdir
|
||||
and lookup, leading to a deadlock in ovl_cache_entry_new, which is called
|
||||
from the filldir, and calls lookup itself.
|
||||
|
||||
--- a/fs/overlayfs/readdir.c
|
||||
+++ b/fs/overlayfs/readdir.c
|
||||
@@ -23,6 +23,7 @@ struct ovl_cache_entry {
|
||||
u64 ino;
|
||||
struct list_head l_node;
|
||||
struct rb_node node;
|
||||
+ struct ovl_cache_entry *next_maybe_whiteout;
|
||||
bool is_whiteout;
|
||||
char name[];
|
||||
};
|
||||
@@ -39,7 +40,7 @@ struct ovl_readdir_data {
|
||||
struct rb_root root;
|
||||
struct list_head *list;
|
||||
struct list_head middle;
|
||||
- struct dentry *dir;
|
||||
+ struct ovl_cache_entry *first_maybe_whiteout;
|
||||
int count;
|
||||
int err;
|
||||
};
|
||||
@@ -79,7 +80,7 @@ static struct ovl_cache_entry *ovl_cache
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static struct ovl_cache_entry *ovl_cache_entry_new(struct dentry *dir,
|
||||
+static struct ovl_cache_entry *ovl_cache_entry_new(struct ovl_readdir_data *rdd,
|
||||
const char *name, int len,
|
||||
u64 ino, unsigned int d_type)
|
||||
{
|
||||
@@ -98,29 +99,8 @@ static struct ovl_cache_entry *ovl_cache
|
||||
p->is_whiteout = false;
|
||||
|
||||
if (d_type == DT_CHR) {
|
||||
- struct dentry *dentry;
|
||||
- const struct cred *old_cred;
|
||||
- struct cred *override_cred;
|
||||
-
|
||||
- override_cred = prepare_creds();
|
||||
- if (!override_cred) {
|
||||
- kfree(p);
|
||||
- return NULL;
|
||||
- }
|
||||
-
|
||||
- /*
|
||||
- * CAP_DAC_OVERRIDE for lookup
|
||||
- */
|
||||
- cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
- old_cred = override_creds(override_cred);
|
||||
-
|
||||
- dentry = lookup_one_len(name, dir, len);
|
||||
- if (!IS_ERR(dentry)) {
|
||||
- p->is_whiteout = ovl_is_whiteout(dentry);
|
||||
- dput(dentry);
|
||||
- }
|
||||
- revert_creds(old_cred);
|
||||
- put_cred(override_cred);
|
||||
+ p->next_maybe_whiteout = rdd->first_maybe_whiteout;
|
||||
+ rdd->first_maybe_whiteout = p;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
@@ -148,7 +128,7 @@ static int ovl_cache_entry_add_rb(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
- p = ovl_cache_entry_new(rdd->dir, name, len, ino, d_type);
|
||||
+ p = ovl_cache_entry_new(rdd, name, len, ino, d_type);
|
||||
if (p == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -169,7 +149,7 @@ static int ovl_fill_lower(struct ovl_rea
|
||||
if (p) {
|
||||
list_move_tail(&p->l_node, &rdd->middle);
|
||||
} else {
|
||||
- p = ovl_cache_entry_new(rdd->dir, name, namelen, ino, d_type);
|
||||
+ p = ovl_cache_entry_new(rdd, name, namelen, ino, d_type);
|
||||
if (p == NULL)
|
||||
rdd->err = -ENOMEM;
|
||||
else
|
||||
@@ -219,6 +199,43 @@ static int ovl_fill_merge(struct dir_con
|
||||
return ovl_fill_lower(rdd, name, namelen, offset, ino, d_type);
|
||||
}
|
||||
|
||||
+static int ovl_check_whiteouts(struct dentry *dir, struct ovl_readdir_data *rdd)
|
||||
+{
|
||||
+ int err = 0;
|
||||
+
|
||||
+ mutex_lock(&dir->d_inode->i_mutex);
|
||||
+ while (rdd->first_maybe_whiteout) {
|
||||
+ struct dentry *dentry;
|
||||
+ const struct cred *old_cred;
|
||||
+ struct cred *override_cred;
|
||||
+ struct ovl_cache_entry *p = rdd->first_maybe_whiteout;
|
||||
+
|
||||
+ rdd->first_maybe_whiteout = p->next_maybe_whiteout;
|
||||
+
|
||||
+ override_cred = prepare_creds();
|
||||
+ if (!override_cred) {
|
||||
+ err = -ENOMEM;
|
||||
+ break;
|
||||
+ }
|
||||
+ /*
|
||||
+ * CAP_DAC_OVERRIDE for lookup
|
||||
+ */
|
||||
+ cap_raise(override_cred->cap_effective, CAP_DAC_OVERRIDE);
|
||||
+ old_cred = override_creds(override_cred);
|
||||
+
|
||||
+ dentry = lookup_one_len(p->name, dir, p->len);
|
||||
+ if (!IS_ERR(dentry)) {
|
||||
+ p->is_whiteout = ovl_is_whiteout(dentry);
|
||||
+ dput(dentry);
|
||||
+ }
|
||||
+ revert_creds(old_cred);
|
||||
+ put_cred(override_cred);
|
||||
+ }
|
||||
+ mutex_unlock(&dir->d_inode->i_mutex);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
static inline int ovl_dir_read(struct path *realpath,
|
||||
struct ovl_readdir_data *rdd)
|
||||
{
|
||||
@@ -229,7 +246,7 @@ static inline int ovl_dir_read(struct pa
|
||||
if (IS_ERR(realfile))
|
||||
return PTR_ERR(realfile);
|
||||
|
||||
- rdd->dir = realpath->dentry;
|
||||
+ rdd->first_maybe_whiteout = NULL;
|
||||
rdd->ctx.pos = 0;
|
||||
do {
|
||||
rdd->count = 0;
|
||||
@@ -238,6 +255,10 @@ static inline int ovl_dir_read(struct pa
|
||||
if (err >= 0)
|
||||
err = rdd->err;
|
||||
} while (!err && rdd->count);
|
||||
+
|
||||
+ if (!err && rdd->first_maybe_whiteout)
|
||||
+ err = ovl_check_whiteouts(realpath->dentry, rdd);
|
||||
+
|
||||
fput(realfile);
|
||||
|
||||
return err;
|
@ -1,41 +0,0 @@
|
||||
From 9612e686b235dc9e33c8dfb5e6d2ff2b2140fb9d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 16 Jun 2015 21:01:30 +0200
|
||||
Subject: [PATCH V2] usb: xhci: make USB_XHCI_PLATFORM selectable
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Right now xhci-plat-hcd can be built when using one of platform specific
|
||||
drivers only (mvebu/rcar). There shouldn't be such limitation as some
|
||||
platforms may not require any quirks and may want to just use a generic
|
||||
driver ("generic-xhci" / "xhci-hcd").
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
Greg/Mathias: I'm not sure if it's more like USB subsystem stuff or xHCI
|
||||
Could you decide which one of you could pick that, please?
|
||||
|
||||
V2: Drop useless "default n", thanks Sergei :)
|
||||
---
|
||||
drivers/usb/host/Kconfig | 9 ++++++++-
|
||||
1 file changed, 8 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/usb/host/Kconfig
|
||||
+++ b/drivers/usb/host/Kconfig
|
||||
@@ -32,7 +32,14 @@ config USB_XHCI_PCI
|
||||
default y
|
||||
|
||||
config USB_XHCI_PLATFORM
|
||||
- tristate
|
||||
+ tristate "Generic xHCI driver for a platform device"
|
||||
+ ---help---
|
||||
+ Adds an xHCI host driver for a generic platform device, which
|
||||
+ provides a memory space and an irq.
|
||||
+ It is also a prerequisite for platform specific drivers that
|
||||
+ implement some extra quirks.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
|
||||
config USB_XHCI_MVEBU
|
||||
tristate "xHCI support for Marvell Armada 375/38x"
|
@ -1,228 +0,0 @@
|
||||
From 4a0e3e989d66bb7204b163d9cfaa7fa96d0f2023 Mon Sep 17 00:00:00 2001
|
||||
From: Enrico Mioso <mrkiko.rs@gmail.com>
|
||||
Date: Wed, 8 Jul 2015 13:05:57 +0200
|
||||
Subject: [PATCH] cdc_ncm: Add support for moving NDP to end of NCM frame
|
||||
|
||||
NCM specs are not actually mandating a specific position in the frame for
|
||||
the NDP (Network Datagram Pointer). However, some Huawei devices will
|
||||
ignore our aggregates if it is not placed after the datagrams it points
|
||||
to. Add support for doing just this, in a per-device configurable way.
|
||||
While at it, update NCM subdrivers, disabling this functionality in all of
|
||||
them, except in huawei_cdc_ncm where it is enabled instead.
|
||||
We aren't making any distinction between different Huawei NCM devices,
|
||||
based on what the vendor driver does. Standard NCM devices are left
|
||||
unaffected: if they are compliant, they should be always usable, still
|
||||
stay on the safe side.
|
||||
|
||||
This change has been tested and working with a Huawei E3131 device (which
|
||||
works regardless of NDP position), a Huawei E3531 (also working both
|
||||
ways) and an E3372 (which mandates NDP to be after indexed datagrams).
|
||||
|
||||
V1->V2:
|
||||
- corrected wrong NDP acronym definition
|
||||
- fixed possible NULL pointer dereference
|
||||
- patch cleanup
|
||||
V2->V3:
|
||||
- Properly account for the NDP size when writing new packets to SKB
|
||||
|
||||
Signed-off-by: Enrico Mioso <mrkiko.rs@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/usb/cdc_mbim.c | 2 +-
|
||||
drivers/net/usb/cdc_ncm.c | 61 ++++++++++++++++++++++++++++++++++++----
|
||||
drivers/net/usb/huawei_cdc_ncm.c | 7 +++--
|
||||
include/linux/usb/cdc_ncm.h | 7 ++++-
|
||||
4 files changed, 67 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/net/usb/cdc_mbim.c
|
||||
+++ b/drivers/net/usb/cdc_mbim.c
|
||||
@@ -158,7 +158,7 @@ static int cdc_mbim_bind(struct usbnet *
|
||||
if (!cdc_ncm_comm_intf_is_mbim(intf->cur_altsetting))
|
||||
goto err;
|
||||
|
||||
- ret = cdc_ncm_bind_common(dev, intf, data_altsetting);
|
||||
+ ret = cdc_ncm_bind_common(dev, intf, data_altsetting, 0);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
--- a/drivers/net/usb/cdc_ncm.c
|
||||
+++ b/drivers/net/usb/cdc_ncm.c
|
||||
@@ -684,10 +684,12 @@ static void cdc_ncm_free(struct cdc_ncm_
|
||||
ctx->tx_curr_skb = NULL;
|
||||
}
|
||||
|
||||
+ kfree(ctx->delayed_ndp16);
|
||||
+
|
||||
kfree(ctx);
|
||||
}
|
||||
|
||||
-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting)
|
||||
+int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags)
|
||||
{
|
||||
const struct usb_cdc_union_desc *union_desc = NULL;
|
||||
struct cdc_ncm_ctx *ctx;
|
||||
@@ -855,6 +857,17 @@ advance:
|
||||
/* finish setting up the device specific data */
|
||||
cdc_ncm_setup(dev);
|
||||
|
||||
+ /* Device-specific flags */
|
||||
+ ctx->drvflags = drvflags;
|
||||
+
|
||||
+ /* Allocate the delayed NDP if needed. */
|
||||
+ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
|
||||
+ ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
|
||||
+ if (!ctx->delayed_ndp16)
|
||||
+ goto error2;
|
||||
+ dev_info(&intf->dev, "NDP will be placed at end of frame for this device.");
|
||||
+ }
|
||||
+
|
||||
/* override ethtool_ops */
|
||||
dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
|
||||
|
||||
@@ -954,8 +967,11 @@ static int cdc_ncm_bind(struct usbnet *d
|
||||
if (cdc_ncm_select_altsetting(intf) != CDC_NCM_COMM_ALTSETTING_NCM)
|
||||
return -ENODEV;
|
||||
|
||||
- /* The NCM data altsetting is fixed */
|
||||
- ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM);
|
||||
+ /* The NCM data altsetting is fixed, so we hard-coded it.
|
||||
+ * Additionally, generic NCM devices are assumed to accept arbitrarily
|
||||
+ * placed NDP.
|
||||
+ */
|
||||
+ ret = cdc_ncm_bind_common(dev, intf, CDC_NCM_DATA_ALTSETTING_NCM, 0);
|
||||
|
||||
/*
|
||||
* We should get an event when network connection is "connected" or
|
||||
@@ -986,6 +1002,14 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
|
||||
struct usb_cdc_ncm_nth16 *nth16 = (void *)skb->data;
|
||||
size_t ndpoffset = le16_to_cpu(nth16->wNdpIndex);
|
||||
|
||||
+ /* If NDP should be moved to the end of the NCM package, we can't follow the
|
||||
+ * NTH16 header as we would normally do. NDP isn't written to the SKB yet, and
|
||||
+ * the wNdpIndex field in the header is actually not consistent with reality. It will be later.
|
||||
+ */
|
||||
+ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
|
||||
+ if (ctx->delayed_ndp16->dwSignature == sign)
|
||||
+ return ctx->delayed_ndp16;
|
||||
+
|
||||
/* follow the chain of NDPs, looking for a match */
|
||||
while (ndpoffset) {
|
||||
ndp16 = (struct usb_cdc_ncm_ndp16 *)(skb->data + ndpoffset);
|
||||
@@ -995,7 +1019,8 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
|
||||
}
|
||||
|
||||
/* align new NDP */
|
||||
- cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
|
||||
+ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
|
||||
+ cdc_ncm_align_tail(skb, ctx->tx_ndp_modulus, 0, ctx->tx_max);
|
||||
|
||||
/* verify that there is room for the NDP and the datagram (reserve) */
|
||||
if ((ctx->tx_max - skb->len - reserve) < ctx->max_ndp_size)
|
||||
@@ -1008,7 +1033,11 @@ static struct usb_cdc_ncm_ndp16 *cdc_ncm
|
||||
nth16->wNdpIndex = cpu_to_le16(skb->len);
|
||||
|
||||
/* push a new empty NDP */
|
||||
- ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
|
||||
+ if (!(ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END))
|
||||
+ ndp16 = (struct usb_cdc_ncm_ndp16 *)memset(skb_put(skb, ctx->max_ndp_size), 0, ctx->max_ndp_size);
|
||||
+ else
|
||||
+ ndp16 = ctx->delayed_ndp16;
|
||||
+
|
||||
ndp16->dwSignature = sign;
|
||||
ndp16->wLength = cpu_to_le16(sizeof(struct usb_cdc_ncm_ndp16) + sizeof(struct usb_cdc_ncm_dpe16));
|
||||
return ndp16;
|
||||
@@ -1023,6 +1052,15 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
|
||||
struct sk_buff *skb_out;
|
||||
u16 n = 0, index, ndplen;
|
||||
u8 ready2send = 0;
|
||||
+ u32 delayed_ndp_size;
|
||||
+
|
||||
+ /* When our NDP gets written in cdc_ncm_ndp(), then skb_out->len gets updated
|
||||
+ * accordingly. Otherwise, we should check here.
|
||||
+ */
|
||||
+ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END)
|
||||
+ delayed_ndp_size = ctx->max_ndp_size;
|
||||
+ else
|
||||
+ delayed_ndp_size = 0;
|
||||
|
||||
/* if there is a remaining skb, it gets priority */
|
||||
if (skb != NULL) {
|
||||
@@ -1077,7 +1115,7 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
|
||||
cdc_ncm_align_tail(skb_out, ctx->tx_modulus, ctx->tx_remainder, ctx->tx_max);
|
||||
|
||||
/* check if we had enough room left for both NDP and frame */
|
||||
- if (!ndp16 || skb_out->len + skb->len > ctx->tx_max) {
|
||||
+ if (!ndp16 || skb_out->len + skb->len + delayed_ndp_size > ctx->tx_max) {
|
||||
if (n == 0) {
|
||||
/* won't fit, MTU problem? */
|
||||
dev_kfree_skb_any(skb);
|
||||
@@ -1150,6 +1188,17 @@ cdc_ncm_fill_tx_frame(struct usbnet *dev
|
||||
/* variables will be reset at next call */
|
||||
}
|
||||
|
||||
+ /* If requested, put NDP at end of frame. */
|
||||
+ if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
|
||||
+ nth16 = (struct usb_cdc_ncm_nth16 *)skb_out->data;
|
||||
+ cdc_ncm_align_tail(skb_out, ctx->tx_ndp_modulus, 0, ctx->tx_max);
|
||||
+ nth16->wNdpIndex = cpu_to_le16(skb_out->len);
|
||||
+ memcpy(skb_put(skb_out, ctx->max_ndp_size), ctx->delayed_ndp16, ctx->max_ndp_size);
|
||||
+
|
||||
+ /* Zero out delayed NDP - signature checking will naturally fail. */
|
||||
+ ndp16 = memset(ctx->delayed_ndp16, 0, ctx->max_ndp_size);
|
||||
+ }
|
||||
+
|
||||
/* If collected data size is less or equal ctx->min_tx_pkt
|
||||
* bytes, we send buffers as it is. If we get more data, it
|
||||
* would be more efficient for USB HS mobile device with DMA
|
||||
--- a/drivers/net/usb/huawei_cdc_ncm.c
|
||||
+++ b/drivers/net/usb/huawei_cdc_ncm.c
|
||||
@@ -73,11 +73,14 @@ static int huawei_cdc_ncm_bind(struct us
|
||||
struct usb_driver *subdriver = ERR_PTR(-ENODEV);
|
||||
int ret = -ENODEV;
|
||||
struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
|
||||
+ int drvflags = 0;
|
||||
|
||||
/* altsetting should always be 1 for NCM devices - so we hard-coded
|
||||
- * it here
|
||||
+ * it here. Some huawei devices will need the NDP part of the NCM package to
|
||||
+ * be at the end of the frame.
|
||||
*/
|
||||
- ret = cdc_ncm_bind_common(usbnet_dev, intf, 1);
|
||||
+ drvflags |= CDC_NCM_FLAG_NDP_TO_END;
|
||||
+ ret = cdc_ncm_bind_common(usbnet_dev, intf, 1, drvflags);
|
||||
if (ret)
|
||||
goto err;
|
||||
|
||||
--- a/include/linux/usb/cdc_ncm.h
|
||||
+++ b/include/linux/usb/cdc_ncm.h
|
||||
@@ -80,6 +80,9 @@
|
||||
#define CDC_NCM_TIMER_INTERVAL_MIN 5UL
|
||||
#define CDC_NCM_TIMER_INTERVAL_MAX (U32_MAX / NSEC_PER_USEC)
|
||||
|
||||
+/* Driver flags */
|
||||
+#define CDC_NCM_FLAG_NDP_TO_END 0x02 /* NDP is placed at end of frame */
|
||||
+
|
||||
#define cdc_ncm_comm_intf_is_mbim(x) ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
|
||||
(x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)
|
||||
#define cdc_ncm_data_intf_is_mbim(x) ((x)->desc.bInterfaceProtocol == USB_CDC_MBIM_PROTO_NTB)
|
||||
@@ -103,9 +106,11 @@ struct cdc_ncm_ctx {
|
||||
|
||||
spinlock_t mtx;
|
||||
atomic_t stop;
|
||||
+ int drvflags;
|
||||
|
||||
u32 timer_interval;
|
||||
u32 max_ndp_size;
|
||||
+ struct usb_cdc_ncm_ndp16 *delayed_ndp16;
|
||||
|
||||
u32 tx_timer_pending;
|
||||
u32 tx_curr_frame_num;
|
||||
@@ -133,7 +138,7 @@ struct cdc_ncm_ctx {
|
||||
};
|
||||
|
||||
u8 cdc_ncm_select_altsetting(struct usb_interface *intf);
|
||||
-int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting);
|
||||
+int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_altsetting, int drvflags);
|
||||
void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf);
|
||||
struct sk_buff *cdc_ncm_fill_tx_frame(struct usbnet *dev, struct sk_buff *skb, __le32 sign);
|
||||
int cdc_ncm_rx_verify_nth16(struct cdc_ncm_ctx *ctx, struct sk_buff *skb_in);
|
@ -1,35 +0,0 @@
|
||||
From a95f03e51471dbdbafd3391991d867ac2358ed02 Mon Sep 17 00:00:00 2001
|
||||
From: Jonas Gorski <jogo@openwrt.org>
|
||||
Date: Sun, 23 Aug 2015 14:23:29 +0200
|
||||
Subject: [PATCH] usb: ehci-orion: fix probe for !GENERIC_PHY
|
||||
|
||||
Commit d445913ce0ab7f ("usb: ehci-orion: add optional PHY support")
|
||||
added support for optional phys, but devm_phy_optional_get returns
|
||||
-ENOSYS if GENERIC_PHY is not enabled.
|
||||
|
||||
This causes probe failures, even when there are no phys specified:
|
||||
|
||||
[ 1.443365] orion-ehci f1058000.usb: init f1058000.usb fail, -38
|
||||
[ 1.449403] orion-ehci: probe of f1058000.usb failed with error -38
|
||||
|
||||
Similar to dwc3, treat -ENOSYS as no phy.
|
||||
|
||||
Fixes: d445913ce0ab7f ("usb: ehci-orion: add optional PHY support")
|
||||
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
drivers/usb/host/ehci-orion.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/usb/host/ehci-orion.c
|
||||
+++ b/drivers/usb/host/ehci-orion.c
|
||||
@@ -218,7 +218,8 @@ static int ehci_orion_drv_probe(struct p
|
||||
priv->phy = devm_phy_optional_get(&pdev->dev, "usb");
|
||||
if (IS_ERR(priv->phy)) {
|
||||
err = PTR_ERR(priv->phy);
|
||||
- goto err_phy_get;
|
||||
+ if (err != -ENOSYS)
|
||||
+ goto err_phy_get;
|
||||
} else {
|
||||
err = phy_init(priv->phy);
|
||||
if (err)
|
@ -1,11 +0,0 @@
|
||||
--- a/scripts/setlocalversion
|
||||
+++ b/scripts/setlocalversion
|
||||
@@ -165,7 +165,7 @@ else
|
||||
# annotated or signed tagged state (as git describe only
|
||||
# looks at signed or annotated tags - git tag -a/-s) and
|
||||
# LOCALVERSION= is not specified
|
||||
- if test "${LOCALVERSION+set}" != "set"; then
|
||||
+ if test "${CONFIG_LOCALVERSION+set}" != "set"; then
|
||||
scm=$(scm_version --short)
|
||||
res="$res${scm:++}"
|
||||
fi
|
@ -1,14 +0,0 @@
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -614,9 +614,9 @@ include $(srctree)/arch/$(SRCARCH)/Makef
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
|
||||
+KBUILD_CFLAGS += -Os $(EXTRA_OPTIMIZATION) $(call cc-disable-warning,maybe-uninitialized,)
|
||||
else
|
||||
-KBUILD_CFLAGS += -O2
|
||||
+KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
|
||||
endif
|
||||
|
||||
# Tell gcc to never replace conditional load with a non-conditional one
|
@ -1,11 +0,0 @@
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -410,7 +410,7 @@ KBUILD_CFLAGS_KERNEL :=
|
||||
KBUILD_AFLAGS := -D__ASSEMBLY__
|
||||
KBUILD_AFLAGS_MODULE := -DMODULE
|
||||
KBUILD_CFLAGS_MODULE := -DMODULE
|
||||
-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
|
||||
+KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
|
||||
|
||||
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
|
||||
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
|
@ -1,108 +0,0 @@
|
||||
--- a/scripts/kallsyms.c
|
||||
+++ b/scripts/kallsyms.c
|
||||
@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
|
||||
static struct sym_entry *table;
|
||||
static unsigned int table_size, table_cnt;
|
||||
static int all_symbols = 0;
|
||||
+static int uncompressed = 0;
|
||||
static int absolute_percpu = 0;
|
||||
static char symbol_prefix_char = '\0';
|
||||
static unsigned long long kernel_start_addr = 0;
|
||||
@@ -392,6 +393,9 @@ static void write_src(void)
|
||||
|
||||
free(markers);
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return;
|
||||
+
|
||||
output_label("kallsyms_token_table");
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -450,6 +454,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];
|
||||
@@ -522,6 +529,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--) {
|
||||
@@ -692,7 +702,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
|
||||
@@ -1324,6 +1324,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
|
||||
the unaligned access emulation.
|
||||
see arch/parisc/kernel/unaligned.c for reference
|
||||
|
||||
+config KALLSYMS_UNCOMPRESSED
|
||||
+ bool "Keep kallsyms uncompressed"
|
||||
+ depends on KALLSYMS
|
||||
+ help
|
||||
+ Normally kallsyms contains compressed symbols (using a token table),
|
||||
+ reducing the uncompressed kernel image size. Keeping the symbol table
|
||||
+ uncompressed significantly improves the size of this part in compressed
|
||||
+ kernel images.
|
||||
+
|
||||
+ Say N unless you need compressed kernel images to be small.
|
||||
+
|
||||
config HAVE_PCSPKR_PLATFORM
|
||||
bool
|
||||
|
||||
--- a/scripts/link-vmlinux.sh
|
||||
+++ b/scripts/link-vmlinux.sh
|
||||
@@ -90,6 +90,10 @@ kallsyms()
|
||||
kallsymopt="${kallsymopt} --absolute-percpu"
|
||||
fi
|
||||
|
||||
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
|
||||
+ kallsymopt="${kallsymopt} --uncompressed"
|
||||
+ fi
|
||||
+
|
||||
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
||||
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
|
||||
|
||||
--- a/kernel/kallsyms.c
|
||||
+++ b/kernel/kallsyms.c
|
||||
@@ -109,6 +109,11 @@ static unsigned int kallsyms_expand_symb
|
||||
* For every byte on the compressed symbol data, copy the table
|
||||
* entry for that byte.
|
||||
*/
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ memcpy(result, data + 1, len - 1);
|
||||
+ result += len - 1;
|
||||
+ len = 0;
|
||||
+#endif
|
||||
while (len) {
|
||||
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
|
||||
data++;
|
||||
@@ -141,6 +146,9 @@ tail:
|
||||
*/
|
||||
static char kallsyms_get_symbol_type(unsigned int off)
|
||||
{
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ return kallsyms_names[off + 1];
|
||||
+#endif
|
||||
/*
|
||||
* Get just the first code, look it up in the token table,
|
||||
* and return the first char from this token.
|
@ -1,194 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
Subject: [PATCH] build: add a hack for removing non-essential module info
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
--- a/include/linux/module.h
|
||||
+++ b/include/linux/module.h
|
||||
@@ -84,9 +84,10 @@ void trim_init_extable(struct module *m)
|
||||
|
||||
/* Generic info of form tag = "info" */
|
||||
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
|
||||
+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
|
||||
|
||||
/* For userspace: you can also call me... */
|
||||
-#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
|
||||
+#define MODULE_ALIAS(_alias) MODULE_INFO_STRIP(alias, _alias)
|
||||
|
||||
/* Soft module dependencies. See man modprobe.d for details.
|
||||
* Example: MODULE_SOFTDEP("pre: module-foo module-bar post: module-baz")
|
||||
@@ -127,12 +128,12 @@ void trim_init_extable(struct module *m)
|
||||
* Author(s), use "Name <email>" or just "Name", for multiple
|
||||
* authors use multiple MODULE_AUTHOR() statements/lines.
|
||||
*/
|
||||
-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
|
||||
+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
|
||||
|
||||
/* What your module does. */
|
||||
-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
|
||||
+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
|
||||
|
||||
-#ifdef MODULE
|
||||
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
extern const typeof(name) __mod_##type##__##name##_device_table \
|
||||
@@ -159,7 +160,9 @@ extern const typeof(name) __mod_##type##
|
||||
*/
|
||||
|
||||
#if defined(MODULE) || !defined(CONFIG_SYSFS)
|
||||
-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
|
||||
+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
|
||||
+#elif defined(CONFIG_MODULE_STRIPPED)
|
||||
+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
|
||||
#else
|
||||
#define MODULE_VERSION(_version) \
|
||||
static struct module_version_attribute ___modver_attr = { \
|
||||
@@ -181,7 +184,7 @@ extern const typeof(name) __mod_##type##
|
||||
/* Optional firmware file (or files) needed by the module
|
||||
* format is simply firmware file name. Multiple firmware
|
||||
* files require multiple MODULE_FIRMWARE() specifiers */
|
||||
-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
|
||||
+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
|
||||
|
||||
/* Given an address, look for it in the exception tables */
|
||||
const struct exception_table_entry *search_exception_tables(unsigned long add);
|
||||
--- a/include/linux/moduleparam.h
|
||||
+++ b/include/linux/moduleparam.h
|
||||
@@ -16,6 +16,16 @@
|
||||
/* Chosen so that structs with an unsigned long line up. */
|
||||
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
|
||||
|
||||
+/* This struct is here for syntactic coherency, it is not used */
|
||||
+#define __MODULE_INFO_DISABLED(name) \
|
||||
+ struct __UNIQUE_ID(name) {}
|
||||
+
|
||||
+#ifdef CONFIG_MODULE_STRIPPED
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
+#else
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
|
||||
+#endif
|
||||
+
|
||||
#ifdef MODULE
|
||||
#define __MODULE_INFO(tag, name, info) \
|
||||
static const char __UNIQUE_ID(name)[] \
|
||||
@@ -23,8 +33,7 @@ static const char __UNIQUE_ID(name)[]
|
||||
= __stringify(tag) "=" info
|
||||
#else /* !MODULE */
|
||||
/* This struct is here for syntactic coherency, it is not used */
|
||||
-#define __MODULE_INFO(tag, name, info) \
|
||||
- struct __UNIQUE_ID(name) {}
|
||||
+#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
#endif
|
||||
#define __MODULE_PARM_TYPE(name, _type) \
|
||||
__MODULE_INFO(parmtype, name##type, #name ":" _type)
|
||||
@@ -32,7 +41,7 @@ static const char __UNIQUE_ID(name)[]
|
||||
/* One for each parameter, describing how to use it. Some files do
|
||||
multiple of these per line, so can't just use MODULE_INFO. */
|
||||
#define MODULE_PARM_DESC(_parm, desc) \
|
||||
- __MODULE_INFO(parm, _parm, #_parm ":" desc)
|
||||
+ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
|
||||
|
||||
struct kernel_param;
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1974,6 +1974,13 @@ config MODULE_COMPRESS_XZ
|
||||
|
||||
endchoice
|
||||
|
||||
+config MODULE_STRIPPED
|
||||
+ bool "Reduce module size"
|
||||
+ depends on MODULES
|
||||
+ help
|
||||
+ Remove module parameter descriptions, author info, version, aliases,
|
||||
+ device tables, etc.
|
||||
+
|
||||
endif # MODULES
|
||||
|
||||
config INIT_ALL_POSSIBLE
|
||||
--- a/kernel/module.c
|
||||
+++ b/kernel/module.c
|
||||
@@ -2680,6 +2680,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;
|
||||
|
||||
@@ -2705,6 +2706,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
|
||||
@@ -1726,7 +1726,9 @@ static void read_symbols(char *modname)
|
||||
symname = remove_dot(info.strtab + sym->st_name);
|
||||
|
||||
handle_modversions(mod, &info, sym, symname);
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
handle_moddevtable(mod, &info, sym, symname);
|
||||
+#endif
|
||||
}
|
||||
if (!is_vmlinux(modname) ||
|
||||
(is_vmlinux(modname) && vmlinux_section_warnings))
|
||||
@@ -1870,7 +1872,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");
|
||||
@@ -1887,16 +1891,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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1989,11 +1997,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)
|
||||
@@ -2224,7 +2234,9 @@ int main(int argc, char **argv)
|
||||
add_staging_flag(&buf, mod->name);
|
||||
err |= add_versions(&buf, mod);
|
||||
add_depends(&buf, mod, modules);
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
add_moddevtable(&buf, mod);
|
||||
+#endif
|
||||
add_srcversion(&buf, mod);
|
||||
|
||||
sprintf(fname, "%s.mod.c", mod->name);
|
@ -1,36 +0,0 @@
|
||||
--- a/lib/vsprintf.c
|
||||
+++ b/lib/vsprintf.c
|
||||
@@ -615,8 +615,10 @@ char *symbol_string(char *buf, char *end
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
unsigned long value;
|
||||
-#ifdef CONFIG_KALLSYMS
|
||||
char sym[KSYM_SYMBOL_LEN];
|
||||
+#ifndef CONFIG_KALLSYMS
|
||||
+ struct module *mod;
|
||||
+ int len;
|
||||
#endif
|
||||
|
||||
if (fmt[1] == 'R')
|
||||
@@ -630,15 +632,15 @@ char *symbol_string(char *buf, char *end
|
||||
sprint_symbol(sym, value);
|
||||
else
|
||||
sprint_symbol_no_offset(sym, value);
|
||||
-
|
||||
- return string(buf, end, sym, spec);
|
||||
#else
|
||||
- spec.field_width = 2 * sizeof(void *);
|
||||
- spec.flags |= SPECIAL | SMALL | ZEROPAD;
|
||||
- spec.base = 16;
|
||||
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
|
||||
|
||||
- return number(buf, end, value, spec);
|
||||
+ mod = __module_address(value);
|
||||
+ if (mod)
|
||||
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
|
||||
+ mod->name, mod->module_core, mod->core_size);
|
||||
#endif
|
||||
+ return string(buf, end, sym, spec);
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
File diff suppressed because it is too large
Load Diff
@ -1,51 +0,0 @@
|
||||
--- a/tools/include/tools/be_byteshift.h
|
||||
+++ b/tools/include/tools/be_byteshift.h
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef _TOOLS_BE_BYTESHIFT_H
|
||||
#define _TOOLS_BE_BYTESHIFT_H
|
||||
|
||||
+#ifndef __linux__
|
||||
+#include "linux_types.h"
|
||||
+#endif
|
||||
+
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint16_t __get_unaligned_be16(const uint8_t *p)
|
||||
--- a/tools/include/tools/le_byteshift.h
|
||||
+++ b/tools/include/tools/le_byteshift.h
|
||||
@@ -1,6 +1,10 @@
|
||||
#ifndef _TOOLS_LE_BYTESHIFT_H
|
||||
#define _TOOLS_LE_BYTESHIFT_H
|
||||
|
||||
+#ifndef __linux__
|
||||
+#include "linux_types.h"
|
||||
+#endif
|
||||
+
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint16_t __get_unaligned_le16(const uint8_t *p)
|
||||
--- /dev/null
|
||||
+++ b/tools/include/tools/linux_types.h
|
||||
@@ -0,0 +1,22 @@
|
||||
+#ifndef __LINUX_TYPES_H
|
||||
+#define __LINUX_TYPES_H
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+typedef uint8_t __u8;
|
||||
+typedef uint8_t __be8;
|
||||
+typedef uint8_t __le8;
|
||||
+
|
||||
+typedef uint16_t __u16;
|
||||
+typedef uint16_t __be16;
|
||||
+typedef uint16_t __le16;
|
||||
+
|
||||
+typedef uint32_t __u32;
|
||||
+typedef uint32_t __be32;
|
||||
+typedef uint32_t __le32;
|
||||
+
|
||||
+typedef uint64_t __u64;
|
||||
+typedef uint64_t __be64;
|
||||
+typedef uint64_t __le64;
|
||||
+
|
||||
+#endif
|
@ -1,11 +0,0 @@
|
||||
--- a/include/uapi/linux/spi/spidev.h
|
||||
+++ b/include/uapi/linux/spi/spidev.h
|
||||
@@ -111,7 +111,7 @@ struct spi_ioc_transfer {
|
||||
|
||||
/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
|
||||
#define SPI_MSGSIZE(N) \
|
||||
- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
|
||||
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
|
||||
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
|
||||
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
|
||||
|
@ -1,532 +0,0 @@
|
||||
From: Felix Fietkau <nbd@openwrt.org>
|
||||
|
||||
use -ffunction-sections, -fdata-sections and --gc-sections
|
||||
|
||||
In combination with kernel symbol export stripping this significantly reduces
|
||||
the kernel image size. Used on both ARM and MIPS architectures.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -89,10 +89,14 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
#
|
||||
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
|
||||
cflags-y += -msoft-float
|
||||
-LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||
+LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
|
||||
+ifndef CONFIG_FUNCTION_TRACER
|
||||
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
+endif
|
||||
+
|
||||
#
|
||||
# pass -msoft-float to GAS if it supports it. However on newer binutils
|
||||
# (specifically newer than 2.24.51.20140728) we then also need to explicitly
|
||||
--- a/arch/mips/kernel/vmlinux.lds.S
|
||||
+++ b/arch/mips/kernel/vmlinux.lds.S
|
||||
@@ -67,7 +67,7 @@ SECTIONS
|
||||
/* Exception table for data bus errors */
|
||||
__dbe_table : {
|
||||
__start___dbe_table = .;
|
||||
- *(__dbe_table)
|
||||
+ KEEP(*(__dbe_table))
|
||||
__stop___dbe_table = .;
|
||||
}
|
||||
|
||||
@@ -112,7 +112,7 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
|
||||
__mips_machines_start = .;
|
||||
- *(.mips.machines.init)
|
||||
+ KEEP(*(.mips.machines.init))
|
||||
__mips_machines_end = .;
|
||||
}
|
||||
|
||||
--- a/include/asm-generic/vmlinux.lds.h
|
||||
+++ b/include/asm-generic/vmlinux.lds.h
|
||||
@@ -89,7 +89,7 @@
|
||||
#ifdef CONFIG_FTRACE_MCOUNT_RECORD
|
||||
#define MCOUNT_REC() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__start_mcount_loc) = .; \
|
||||
- *(__mcount_loc) \
|
||||
+ KEEP(*(__mcount_loc)) \
|
||||
VMLINUX_SYMBOL(__stop_mcount_loc) = .;
|
||||
#else
|
||||
#define MCOUNT_REC()
|
||||
@@ -97,7 +97,7 @@
|
||||
|
||||
#ifdef CONFIG_TRACE_BRANCH_PROFILING
|
||||
#define LIKELY_PROFILE() VMLINUX_SYMBOL(__start_annotated_branch_profile) = .; \
|
||||
- *(_ftrace_annotated_branch) \
|
||||
+ KEEP(*(_ftrace_annotated_branch)) \
|
||||
VMLINUX_SYMBOL(__stop_annotated_branch_profile) = .;
|
||||
#else
|
||||
#define LIKELY_PROFILE()
|
||||
@@ -105,7 +105,7 @@
|
||||
|
||||
#ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||
#define BRANCH_PROFILE() VMLINUX_SYMBOL(__start_branch_profile) = .; \
|
||||
- *(_ftrace_branch) \
|
||||
+ KEEP(*(_ftrace_branch)) \
|
||||
VMLINUX_SYMBOL(__stop_branch_profile) = .;
|
||||
#else
|
||||
#define BRANCH_PROFILE()
|
||||
@@ -114,7 +114,7 @@
|
||||
#ifdef CONFIG_KPROBES
|
||||
#define KPROBE_BLACKLIST() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
|
||||
- *(_kprobe_blacklist) \
|
||||
+ KEEP(*(_kprobe_blacklist)) \
|
||||
VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
|
||||
#else
|
||||
#define KPROBE_BLACKLIST()
|
||||
@@ -123,7 +123,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()
|
||||
@@ -131,7 +131,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 */ \
|
||||
@@ -144,7 +144,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()
|
||||
@@ -158,8 +158,8 @@
|
||||
#define _OF_TABLE_1(name) \
|
||||
. = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__##name##_of_table) = .; \
|
||||
- *(__##name##_of_table) \
|
||||
- *(__##name##_of_table_end)
|
||||
+ KEEP(*(__##name##_of_table)) \
|
||||
+ KEEP(*(__##name##_of_table_end))
|
||||
|
||||
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
|
||||
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
|
||||
@@ -172,7 +172,7 @@
|
||||
#define KERNEL_DTB() \
|
||||
STRUCT_ALIGN(); \
|
||||
VMLINUX_SYMBOL(__dtb_start) = .; \
|
||||
- *(.dtb.init.rodata) \
|
||||
+ KEEP(*(.dtb.init.rodata)) \
|
||||
VMLINUX_SYMBOL(__dtb_end) = .;
|
||||
|
||||
/* .data section */
|
||||
@@ -188,16 +188,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
|
||||
@@ -251,35 +252,35 @@
|
||||
/* PCI quirks */ \
|
||||
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
|
||||
- *(.pci_fixup_early) \
|
||||
+ KEEP(*(.pci_fixup_early)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \
|
||||
- *(.pci_fixup_header) \
|
||||
+ KEEP(*(.pci_fixup_header)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \
|
||||
- *(.pci_fixup_final) \
|
||||
+ KEEP(*(.pci_fixup_final)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \
|
||||
- *(.pci_fixup_enable) \
|
||||
+ KEEP(*(.pci_fixup_enable)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \
|
||||
- *(.pci_fixup_resume) \
|
||||
+ KEEP(*(.pci_fixup_resume)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \
|
||||
- *(.pci_fixup_resume_early) \
|
||||
+ KEEP(*(.pci_fixup_resume_early)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
|
||||
- *(.pci_fixup_suspend) \
|
||||
+ KEEP(*(.pci_fixup_suspend)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
|
||||
VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \
|
||||
- *(.pci_fixup_suspend_late) \
|
||||
+ KEEP(*(.pci_fixup_suspend_late)) \
|
||||
VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
|
||||
} \
|
||||
\
|
||||
/* Built-in firmware blobs */ \
|
||||
.builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__start_builtin_fw) = .; \
|
||||
- *(.builtin_fw) \
|
||||
+ KEEP(*(.builtin_fw)) \
|
||||
VMLINUX_SYMBOL(__end_builtin_fw) = .; \
|
||||
} \
|
||||
\
|
||||
@@ -288,49 +289,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) = .; \
|
||||
} \
|
||||
\
|
||||
@@ -344,14 +345,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) = .; \
|
||||
} \
|
||||
\
|
||||
@@ -370,14 +371,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) = .; \
|
||||
@@ -433,7 +434,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
|
||||
@@ -461,7 +462,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) = .; \
|
||||
}
|
||||
|
||||
@@ -477,9 +478,9 @@
|
||||
#ifdef CONFIG_CONSTRUCTORS
|
||||
#define KERNEL_CTORS() . = ALIGN(8); \
|
||||
VMLINUX_SYMBOL(__ctors_start) = .; \
|
||||
- *(.ctors) \
|
||||
+ KEEP(*(.ctors)) \
|
||||
*(SORT(.init_array.*)) \
|
||||
- *(.init_array) \
|
||||
+ KEEP(*(.init_array)) \
|
||||
VMLINUX_SYMBOL(__ctors_end) = .;
|
||||
#else
|
||||
#define KERNEL_CTORS()
|
||||
@@ -528,7 +529,7 @@
|
||||
#define SBSS(sbss_align) \
|
||||
. = ALIGN(sbss_align); \
|
||||
.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \
|
||||
- *(.sbss) \
|
||||
+ *(.sbss .sbss.*) \
|
||||
*(.scommon) \
|
||||
}
|
||||
|
||||
@@ -546,7 +547,7 @@
|
||||
BSS_FIRST_SECTIONS \
|
||||
*(.bss..page_aligned) \
|
||||
*(.dynbss) \
|
||||
- *(.bss) \
|
||||
+ *(.bss .bss.*) \
|
||||
*(COMMON) \
|
||||
}
|
||||
|
||||
@@ -595,7 +596,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
|
||||
@@ -607,7 +608,7 @@
|
||||
. = ALIGN(4); \
|
||||
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \
|
||||
VMLINUX_SYMBOL(__tracedata_start) = .; \
|
||||
- *(.tracedata) \
|
||||
+ KEEP(*(.tracedata)) \
|
||||
VMLINUX_SYMBOL(__tracedata_end) = .; \
|
||||
}
|
||||
#else
|
||||
@@ -624,17 +625,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) \
|
||||
@@ -648,21 +649,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
|
||||
|
||||
OBJCOPYFLAGS :=-O binary -R .comment -S
|
||||
GZFLAGS :=-9
|
||||
#KBUILD_CFLAGS +=-pipe
|
||||
|
||||
+ifndef CONFIG_FUNCTION_TRACER
|
||||
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
+endif
|
||||
+
|
||||
# Never generate .eh_frame
|
||||
KBUILD_CFLAGS += $(call cc-option,-fno-dwarf2-cfi-asm)
|
||||
|
||||
--- a/arch/arm/kernel/vmlinux.lds.S
|
||||
+++ b/arch/arm/kernel/vmlinux.lds.S
|
||||
@@ -15,13 +15,13 @@
|
||||
#define PROC_INFO \
|
||||
. = ALIGN(4); \
|
||||
VMLINUX_SYMBOL(__proc_info_begin) = .; \
|
||||
- *(.proc.info.init) \
|
||||
+ KEEP(*(.proc.info.init)) \
|
||||
VMLINUX_SYMBOL(__proc_info_end) = .;
|
||||
|
||||
#define IDMAP_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
VMLINUX_SYMBOL(__idmap_text_start) = .; \
|
||||
- *(.idmap.text) \
|
||||
+ KEEP(*(.idmap.text)) \
|
||||
VMLINUX_SYMBOL(__idmap_text_end) = .; \
|
||||
. = ALIGN(32); \
|
||||
VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
|
||||
@@ -101,7 +101,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
|
||||
@@ -129,7 +129,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 = .;
|
||||
}
|
||||
@@ -141,12 +141,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
|
||||
@@ -169,14 +169,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 = .;
|
||||
@@ -190,24 +190,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
|
||||
@@ -122,6 +122,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
|
||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
||||
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
|
||||
endif
|
||||
+KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
|
||||
|
||||
ccflags-y := -fpic -mno-single-pic-base -fno-builtin -I$(obj)
|
||||
asflags-y := -DZIMAGE
|
@ -1,88 +0,0 @@
|
||||
--- a/include/asm-generic/vmlinux.lds.h
|
||||
+++ b/include/asm-generic/vmlinux.lds.h
|
||||
@@ -54,6 +54,16 @@
|
||||
#define LOAD_OFFSET 0
|
||||
#endif
|
||||
|
||||
+#ifndef SYMTAB_KEEP
|
||||
+#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
|
||||
+#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
|
||||
+#endif
|
||||
+
|
||||
+#ifndef SYMTAB_DISCARD
|
||||
+#define SYMTAB_DISCARD
|
||||
+#define SYMTAB_DISCARD_GPL
|
||||
+#endif
|
||||
+
|
||||
#include <linux/export.h>
|
||||
|
||||
/* Align . to a 8 byte boundary equals to maximum function alignment. */
|
||||
@@ -289,14 +299,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) = .; \
|
||||
} \
|
||||
\
|
||||
@@ -358,7 +368,7 @@
|
||||
\
|
||||
/* Kernel symbol table: strings */ \
|
||||
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||
- *(__ksymtab_strings) \
|
||||
+ *(__ksymtab_strings+*) \
|
||||
} \
|
||||
\
|
||||
/* __*init sections */ \
|
||||
@@ -682,6 +692,8 @@
|
||||
EXIT_TEXT \
|
||||
EXIT_DATA \
|
||||
EXIT_CALL \
|
||||
+ SYMTAB_DISCARD \
|
||||
+ SYMTAB_DISCARD_GPL \
|
||||
*(.discard) \
|
||||
*(.discard.*) \
|
||||
}
|
||||
--- a/scripts/Makefile.build
|
||||
+++ b/scripts/Makefile.build
|
||||
@@ -299,7 +299,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
|
||||
# Linker scripts preprocessor (.lds.S -> .lds)
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_cpp_lds_S = LDS $@
|
||||
- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -C -U$(ARCH) \
|
||||
+ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
|
||||
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
|
||||
|
||||
$(obj)/%.lds: $(src)/%.lds.S FORCE
|
||||
--- a/include/linux/export.h
|
||||
+++ b/include/linux/export.h
|
||||
@@ -52,12 +52,19 @@ extern struct module __this_module;
|
||||
#define __CRC_SYMBOL(sym, sec)
|
||||
#endif
|
||||
|
||||
+#ifdef MODULE
|
||||
+#define __EXPORT_SUFFIX(sym)
|
||||
+#else
|
||||
+#define __EXPORT_SUFFIX(sym) "+" #sym
|
||||
+#endif
|
||||
+
|
||||
/* For every exported symbol, place a struct in the __ksymtab section */
|
||||
#define __EXPORT_SYMBOL(sym, sec) \
|
||||
extern typeof(sym) sym; \
|
||||
__CRC_SYMBOL(sym, sec) \
|
||||
static const char __kstrtab_##sym[] \
|
||||
- __attribute__((section("__ksymtab_strings"), aligned(1))) \
|
||||
+ __attribute__((section("__ksymtab_strings" \
|
||||
+ __EXPORT_SUFFIX(sym)), aligned(1))) \
|
||||
= VMLINUX_SYMBOL_STR(sym); \
|
||||
extern const struct kernel_symbol __ksymtab_##sym; \
|
||||
__visible const struct kernel_symbol __ksymtab_##sym \
|
@ -1,58 +0,0 @@
|
||||
--- a/scripts/Makefile.lib
|
||||
+++ b/scripts/Makefile.lib
|
||||
@@ -323,7 +323,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
|
||||
|
||||
quiet_cmd_lzma = LZMA $@
|
||||
cmd_lzma = (cat $(filter-out FORCE,$^) | \
|
||||
- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
+ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
quiet_cmd_lzo = LZO $@
|
||||
--- a/scripts/gen_initramfs_list.sh
|
||||
+++ b/scripts/gen_initramfs_list.sh
|
||||
@@ -226,7 +226,7 @@ cpio_list=
|
||||
output="/dev/stdout"
|
||||
output_file=""
|
||||
is_cpio_compressed=
|
||||
-compr="gzip -n -9 -f"
|
||||
+compr="gzip -n -9 -f -"
|
||||
|
||||
arg="$1"
|
||||
case "$arg" in
|
||||
@@ -242,13 +242,13 @@ case "$arg" in
|
||||
output=${cpio_list}
|
||||
echo "$output_file" | grep -q "\.gz$" \
|
||||
&& [ -x "`which gzip 2> /dev/null`" ] \
|
||||
- && compr="gzip -n -9 -f"
|
||||
+ && compr="gzip -n -9 -f -"
|
||||
echo "$output_file" | grep -q "\.bz2$" \
|
||||
&& [ -x "`which bzip2 2> /dev/null`" ] \
|
||||
- && compr="bzip2 -9 -f"
|
||||
+ && compr="bzip2 -9 -f -"
|
||||
echo "$output_file" | grep -q "\.lzma$" \
|
||||
&& [ -x "`which lzma 2> /dev/null`" ] \
|
||||
- && compr="lzma -9 -f"
|
||||
+ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
|
||||
echo "$output_file" | grep -q "\.xz$" \
|
||||
&& [ -x "`which xz 2> /dev/null`" ] \
|
||||
&& compr="xz --check=crc32 --lzma2=dict=1MiB"
|
||||
@@ -315,7 +315,7 @@ if [ ! -z ${output_file} ]; then
|
||||
if [ "${is_cpio_compressed}" = "compressed" ]; then
|
||||
cat ${cpio_tfile} > ${output_file}
|
||||
else
|
||||
- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \
|
||||
+ (cat ${cpio_tfile} | ${compr} > ${output_file}) \
|
||||
|| (rm -f ${output_file} ; false)
|
||||
fi
|
||||
[ -z ${cpio_file} ] && rm ${cpio_tfile}
|
||||
--- a/lib/decompress.c
|
||||
+++ b/lib/decompress.c
|
||||
@@ -48,6 +48,7 @@ static const struct compress_format comp
|
||||
{ {0x1f, 0x9e}, "gzip", gunzip },
|
||||
{ {0x42, 0x5a}, "bzip2", bunzip2 },
|
||||
{ {0x5d, 0x00}, "lzma", unlzma },
|
||||
+ { {0x6d, 0x00}, "lzma-openwrt", unlzma },
|
||||
{ {0xfd, 0x37}, "xz", unxz },
|
||||
{ {0x89, 0x4c}, "lzo", unlzo },
|
||||
{ {0x02, 0x21}, "lz4", unlz4 },
|
@ -1,18 +0,0 @@
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -210,7 +210,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
|
||||
@@ -924,7 +923,6 @@ config NETFILTER_XT_TARGET_SECMARK
|
||||
|
||||
config NETFILTER_XT_TARGET_TCPMSS
|
||||
tristate '"TCPMSS" target support'
|
||||
- depends on (IPV6 || IPV6=n)
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
---help---
|
||||
This option adds a `TCPMSS' target, which allows you to alter the
|
@ -1,18 +0,0 @@
|
||||
--- a/sound/core/Kconfig
|
||||
+++ b/sound/core/Kconfig
|
||||
@@ -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
|
@ -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
|
@ -1,29 +0,0 @@
|
||||
--- a/drivers/ssb/Kconfig
|
||||
+++ b/drivers/ssb/Kconfig
|
||||
@@ -29,6 +29,7 @@ config SSB_SPROM
|
||||
config SSB_BLOCKIO
|
||||
bool
|
||||
depends on SSB
|
||||
+ default y
|
||||
|
||||
config SSB_PCIHOST_POSSIBLE
|
||||
bool
|
||||
@@ -49,7 +50,7 @@ config SSB_PCIHOST
|
||||
config SSB_B43_PCI_BRIDGE
|
||||
bool
|
||||
depends on SSB_PCIHOST
|
||||
- default n
|
||||
+ default y
|
||||
|
||||
config SSB_PCMCIAHOST_POSSIBLE
|
||||
bool
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -17,6 +17,7 @@ config BCMA
|
||||
config BCMA_BLOCKIO
|
||||
bool
|
||||
depends on BCMA
|
||||
+ default y
|
||||
|
||||
config BCMA_HOST_PCI_POSSIBLE
|
||||
bool
|
@ -1,23 +0,0 @@
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -329,16 +329,16 @@ config BCH_CONST_T
|
||||
# Textsearch support is select'ed if needed
|
||||
#
|
||||
config TEXTSEARCH
|
||||
- bool
|
||||
+ boolean "Textsearch support"
|
||||
|
||||
config TEXTSEARCH_KMP
|
||||
- tristate
|
||||
+ tristate "Textsearch KMP"
|
||||
|
||||
config TEXTSEARCH_BM
|
||||
- tristate
|
||||
+ tristate "Textsearch BM"
|
||||
|
||||
config TEXTSEARCH_FSM
|
||||
- tristate
|
||||
+ tristate "Textsearch FSM"
|
||||
|
||||
config BTREE
|
||||
bool
|
@ -1,31 +0,0 @@
|
||||
--- a/net/wireless/Kconfig
|
||||
+++ b/net/wireless/Kconfig
|
||||
@@ -183,7 +183,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
|
||||
@@ -192,13 +192,16 @@ config LIB80211
|
||||
Drivers should select this themselves if needed.
|
||||
|
||||
config LIB80211_CRYPT_WEP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_WEP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_CRYPT_CCMP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_CCMP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_CRYPT_TKIP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_TKIP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_DEBUG
|
||||
bool "lib80211 debugging messages"
|
@ -1,47 +0,0 @@
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -32,7 +32,7 @@ config CRYPTO_FIPS
|
||||
this is.
|
||||
|
||||
config CRYPTO_ALGAPI
|
||||
- tristate
|
||||
+ tristate "ALGAPI"
|
||||
select CRYPTO_ALGAPI2
|
||||
help
|
||||
This option provides the API for cryptographic algorithms.
|
||||
@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
|
||||
tristate
|
||||
|
||||
config CRYPTO_AEAD
|
||||
- tristate
|
||||
+ tristate "AEAD"
|
||||
select CRYPTO_AEAD2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -50,7 +50,7 @@ config CRYPTO_AEAD2
|
||||
select CRYPTO_ALGAPI2
|
||||
|
||||
config CRYPTO_BLKCIPHER
|
||||
- tristate
|
||||
+ tristate "BLKCIPHER"
|
||||
select CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -61,7 +61,7 @@ config CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_WORKQUEUE
|
||||
|
||||
config CRYPTO_HASH
|
||||
- tristate
|
||||
+ tristate "HASH"
|
||||
select CRYPTO_HASH2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -70,7 +70,7 @@ config CRYPTO_HASH2
|
||||
select CRYPTO_ALGAPI2
|
||||
|
||||
config CRYPTO_RNG
|
||||
- tristate
|
||||
+ tristate "RNG"
|
||||
select CRYPTO_RNG2
|
||||
select CRYPTO_ALGAPI
|
||||
|
@ -1,22 +0,0 @@
|
||||
--- a/net/wireless/Kconfig
|
||||
+++ b/net/wireless/Kconfig
|
||||
@@ -1,5 +1,5 @@
|
||||
config WIRELESS_EXT
|
||||
- bool
|
||||
+ bool "Wireless extensions"
|
||||
|
||||
config WEXT_CORE
|
||||
def_bool y
|
||||
@@ -11,10 +11,10 @@ config WEXT_PROC
|
||||
depends on WEXT_CORE
|
||||
|
||||
config WEXT_SPY
|
||||
- bool
|
||||
+ bool "WEXT_SPY"
|
||||
|
||||
config WEXT_PRIV
|
||||
- bool
|
||||
+ bool "WEXT_PRIV"
|
||||
|
||||
config CFG80211
|
||||
tristate "cfg80211 - wireless configuration API"
|
@ -1,11 +0,0 @@
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -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"
|
@ -1,84 +0,0 @@
|
||||
--- a/drivers/base/regmap/Kconfig
|
||||
+++ b/drivers/base/regmap/Kconfig
|
||||
@@ -3,29 +3,35 @@
|
||||
# subsystems should select the appropriate symbols.
|
||||
|
||||
config REGMAP
|
||||
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
|
||||
select LZO_COMPRESS
|
||||
select LZO_DECOMPRESS
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
- bool
|
||||
+ tristate "Regmap"
|
||||
|
||||
config REGMAP_AC97
|
||||
+ select REGMAP
|
||||
tristate
|
||||
|
||||
config REGMAP_I2C
|
||||
- tristate
|
||||
+ tristate "Regmap I2C"
|
||||
+ select REGMAP
|
||||
depends on I2C
|
||||
|
||||
config REGMAP_SPI
|
||||
- tristate
|
||||
+ tristate "Regmap SPI"
|
||||
+ select REGMAP
|
||||
+ depends on SPI_MASTER
|
||||
depends on SPI
|
||||
|
||||
config REGMAP_SPMI
|
||||
+ select REGMAP
|
||||
tristate
|
||||
depends on SPMI
|
||||
|
||||
config REGMAP_MMIO
|
||||
- tristate
|
||||
+ tristate "Regmap MMIO"
|
||||
+ select REGMAP
|
||||
|
||||
config REGMAP_IRQ
|
||||
+ select REGMAP
|
||||
bool
|
||||
--- a/include/linux/regmap.h
|
||||
+++ b/include/linux/regmap.h
|
||||
@@ -50,7 +50,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_AC97) += regmap-ac97.o
|
||||
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
|
||||
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
|
||||
--- a/drivers/base/regmap/regmap.c
|
||||
+++ b/drivers/base/regmap/regmap.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
@@ -2631,3 +2632,5 @@ static int __init regmap_initcall(void)
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(regmap_initcall);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
@ -1,37 +0,0 @@
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -96,10 +96,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;
|
||||
|
@ -1,35 +0,0 @@
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -214,25 +214,25 @@ 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
|
||||
+ tristate "LZ4 compress support"
|
||||
|
||||
config LZ4HC_COMPRESS
|
||||
- tristate
|
||||
+ tristate "LZ4HC compress support"
|
||||
|
||||
config LZ4_DECOMPRESS
|
||||
- tristate
|
||||
+ tristate "LZ4 decompress support"
|
||||
|
||||
source "lib/xz/Kconfig"
|
||||
|
@ -1,34 +0,0 @@
|
||||
From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Date: Mon, 29 Jun 2015 14:37:54 +0200
|
||||
Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
|
||||
|
||||
including sysinfo.h from kernel.h makes no sense whatsoever,
|
||||
but removing it breaks glibc's userspace header,
|
||||
which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
|
||||
this seems to be a historical mistake.
|
||||
on musl, including any header that uses kernel.h directly or indirectly
|
||||
plus sys/sysinfo.h will produce a compile error due to redefinition of
|
||||
struct sysinfo from sys/sysinfo.h.
|
||||
so for now, only include it on glibc or when including from kernel
|
||||
in order not to break their headers.
|
||||
|
||||
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||
Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
include/uapi/linux/kernel.h | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/include/uapi/linux/kernel.h
|
||||
+++ b/include/uapi/linux/kernel.h
|
||||
@@ -1,7 +1,9 @@
|
||||
#ifndef _UAPI_LINUX_KERNEL_H
|
||||
#define _UAPI_LINUX_KERNEL_H
|
||||
|
||||
+#if defined(__KERNEL__) || defined( __GLIBC__)
|
||||
#include <linux/sysinfo.h>
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* 'kernel.h' contains some often-used function prototypes etc
|
@ -1,81 +0,0 @@
|
||||
From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Date: Mon, 29 Jun 2015 16:50:40 +0200
|
||||
Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
|
||||
|
||||
Musl provides the same structs as glibc, but does not provide a define to
|
||||
allow its detection. Since the absence of __GLIBC__ also can mean that it
|
||||
is included from the kernel, change the __GLIBC__ detection to
|
||||
!__KERNEL__, which should always be true when included from userspace.
|
||||
|
||||
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
include/uapi/linux/libc-compat.h | 18 +++++++++---------
|
||||
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/include/uapi/linux/libc-compat.h
|
||||
+++ b/include/uapi/linux/libc-compat.h
|
||||
@@ -48,13 +48,13 @@
|
||||
#ifndef _UAPI_LIBC_COMPAT_H
|
||||
#define _UAPI_LIBC_COMPAT_H
|
||||
|
||||
-/* We have included glibc headers... */
|
||||
-#if defined(__GLIBC__)
|
||||
+/* We have included libc headers... */
|
||||
+#if !defined(__KERNEL__)
|
||||
|
||||
-/* Coordinate with glibc netinet/in.h header. */
|
||||
+/* Coordinate with libc netinet/in.h header. */
|
||||
#if defined(_NETINET_IN_H)
|
||||
|
||||
-/* GLIBC headers included first so don't define anything
|
||||
+/* LIBC headers included first so don't define anything
|
||||
* that would already be defined. */
|
||||
#define __UAPI_DEF_IN_ADDR 0
|
||||
#define __UAPI_DEF_IN_IPPROTO 0
|
||||
@@ -68,7 +68,7 @@
|
||||
* if the glibc code didn't define them. This guard matches
|
||||
* the guard in glibc/inet/netinet/in.h which defines the
|
||||
* additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
|
||||
-#if defined(__USE_MISC) || defined (__USE_GNU)
|
||||
+#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
|
||||
#define __UAPI_DEF_IN6_ADDR_ALT 0
|
||||
#else
|
||||
#define __UAPI_DEF_IN6_ADDR_ALT 1
|
||||
@@ -83,7 +83,7 @@
|
||||
#else
|
||||
|
||||
/* Linux headers included first, and we must define everything
|
||||
- * we need. The expectation is that glibc will check the
|
||||
+ * we need. The expectation is that the libc will check the
|
||||
* __UAPI_DEF_* defines and adjust appropriately. */
|
||||
#define __UAPI_DEF_IN_ADDR 1
|
||||
#define __UAPI_DEF_IN_IPPROTO 1
|
||||
@@ -93,7 +93,7 @@
|
||||
#define __UAPI_DEF_IN_CLASS 1
|
||||
|
||||
#define __UAPI_DEF_IN6_ADDR 1
|
||||
-/* We unconditionally define the in6_addr macros and glibc must
|
||||
+/* We unconditionally define the in6_addr macros and the libc must
|
||||
* coordinate. */
|
||||
#define __UAPI_DEF_IN6_ADDR_ALT 1
|
||||
#define __UAPI_DEF_SOCKADDR_IN6 1
|
||||
@@ -115,7 +115,7 @@
|
||||
/* If we did not see any headers from any supported C libraries,
|
||||
* or we are being included in the kernel, then define everything
|
||||
* that we need. */
|
||||
-#else /* !defined(__GLIBC__) */
|
||||
+#else /* defined(__KERNEL__) */
|
||||
|
||||
/* Definitions for in.h */
|
||||
#define __UAPI_DEF_IN_ADDR 1
|
||||
@@ -138,6 +138,6 @@
|
||||
/* Definitions for xattr.h */
|
||||
#define __UAPI_DEF_XATTR 1
|
||||
|
||||
-#endif /* __GLIBC__ */
|
||||
+#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _UAPI_LIBC_COMPAT_H */
|
@ -1,67 +0,0 @@
|
||||
From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Date: Mon, 29 Jun 2015 16:53:03 +0200
|
||||
Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
|
||||
|
||||
Musl provides its own ethhdr struct definition. Add a guard to prevent
|
||||
its definition of the appropriate musl header has already been included.
|
||||
|
||||
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
include/uapi/linux/if_ether.h | 3 +++
|
||||
include/uapi/linux/libc-compat.h | 11 +++++++++++
|
||||
2 files changed, 14 insertions(+)
|
||||
|
||||
--- a/include/uapi/linux/if_ether.h
|
||||
+++ b/include/uapi/linux/if_ether.h
|
||||
@@ -22,6 +22,7 @@
|
||||
#define _UAPI_LINUX_IF_ETHER_H
|
||||
|
||||
#include <linux/types.h>
|
||||
+#include <linux/libc-compat.h>
|
||||
|
||||
/*
|
||||
* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
|
||||
@@ -134,11 +135,13 @@
|
||||
* This is an Ethernet frame header.
|
||||
*/
|
||||
|
||||
+#if __UAPI_DEF_ETHHDR
|
||||
struct ethhdr {
|
||||
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
|
||||
unsigned char h_source[ETH_ALEN]; /* source ether addr */
|
||||
__be16 h_proto; /* packet type ID field */
|
||||
} __attribute__((packed));
|
||||
+#endif
|
||||
|
||||
|
||||
#endif /* _UAPI_LINUX_IF_ETHER_H */
|
||||
--- a/include/uapi/linux/libc-compat.h
|
||||
+++ b/include/uapi/linux/libc-compat.h
|
||||
@@ -51,6 +51,14 @@
|
||||
/* We have included libc headers... */
|
||||
#if !defined(__KERNEL__)
|
||||
|
||||
+/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
|
||||
+ * Glibc just includes the kernel header and uses a different guard. */
|
||||
+#if defined(_NETINET_IF_ETHER_H)
|
||||
+#define __UAPI_DEF_ETHHDR 0
|
||||
+#else
|
||||
+#define __UAPI_DEF_ETHHDR 1
|
||||
+#endif
|
||||
+
|
||||
/* Coordinate with libc netinet/in.h header. */
|
||||
#if defined(_NETINET_IN_H)
|
||||
|
||||
@@ -117,6 +125,9 @@
|
||||
* that we need. */
|
||||
#else /* defined(__KERNEL__) */
|
||||
|
||||
+/* Definitions for if_ether.h */
|
||||
+#define __UAPI_DEF_ETHHDR 1
|
||||
+
|
||||
/* Definitions for in.h */
|
||||
#define __UAPI_DEF_IN_ADDR 1
|
||||
#define __UAPI_DEF_IN_IPPROTO 1
|
@ -1,39 +0,0 @@
|
||||
From: Mark Miller <mark@mirell.org>
|
||||
|
||||
This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
|
||||
certain Broadcom chipsets running CFE in order to load the kernel.
|
||||
|
||||
Signed-off-by: Mark Miller <mark@mirell.org>
|
||||
Acked-by: Rob Landley <rob@landley.net>
|
||||
---
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -941,9 +941,6 @@ config FW_ARC
|
||||
config ARCH_MAY_HAVE_PC_FDC
|
||||
bool
|
||||
|
||||
-config BOOT_RAW
|
||||
- bool
|
||||
-
|
||||
config CEVT_BCM1480
|
||||
bool
|
||||
|
||||
@@ -2594,6 +2591,18 @@ config USE_OF
|
||||
config BUILTIN_DTB
|
||||
bool
|
||||
|
||||
+config BOOT_RAW
|
||||
+ bool "Enable the kernel to be executed from the load address"
|
||||
+ default n
|
||||
+ help
|
||||
+ Allow the kernel to be executed from the load address for
|
||||
+ bootloaders which cannot read the ELF format. This places
|
||||
+ a jump to start_kernel at the load address.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
+
|
||||
+
|
||||
endmenu
|
||||
|
||||
config LOCKDEP_SUPPORT
|
@ -1,28 +0,0 @@
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -1030,6 +1030,10 @@ config SYNC_R4K
|
||||
config MIPS_MACHINE
|
||||
def_bool n
|
||||
|
||||
+config IMAGE_CMDLINE_HACK
|
||||
+ bool "OpenWrt specific image command line hack"
|
||||
+ default n
|
||||
+
|
||||
config NO_IOPORT_MAP
|
||||
def_bool n
|
||||
|
||||
--- a/arch/mips/kernel/head.S
|
||||
+++ b/arch/mips/kernel/head.S
|
||||
@@ -80,6 +80,12 @@ FEXPORT(__kernel_entry)
|
||||
j kernel_entry
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
|
||||
+ .ascii "CMDLINE:"
|
||||
+EXPORT(__image_cmdline)
|
||||
+ .fill 0x400
|
||||
+#endif /* CONFIG_IMAGE_CMDLINE_HACK */
|
||||
+
|
||||
__REF
|
||||
|
||||
NESTED(kernel_entry, 16, sp) # kernel entry point
|
@ -1,11 +0,0 @@
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -87,7 +87,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
# machines may also. Since BFD is incredibly buggy with respect to
|
||||
# crossformat linking we rely on the elf2ecoff tool for format conversion.
|
||||
#
|
||||
-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
|
||||
+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
@ -1,105 +0,0 @@
|
||||
From: Manuel Lauss <manuel.lauss@gmail.com>
|
||||
Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
|
||||
Date: Mon, 7 Apr 2014 12:57:04 +0200
|
||||
Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
|
||||
|
||||
This small patch makes the MIPS FPU emulator optional. The kernel
|
||||
kills float-users on systems without a hardware FPU by sending a SIGILL.
|
||||
|
||||
Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
|
||||
optimizing for size).
|
||||
|
||||
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
|
||||
---
|
||||
v4: rediffed because of patch 1/2, should now work with micromips as well
|
||||
v3: updated patch description with size savings.
|
||||
v2: incorporated changes suggested by Jonas Gorski
|
||||
force the fpu emulator on for micromips: relocating the parts
|
||||
of the mmips code in the emulator to other areas would be a
|
||||
much larger change; I went the cheap route instead with this.
|
||||
|
||||
arch/mips/Kbuild | 2 +-
|
||||
arch/mips/Kconfig | 14 ++++++++++++++
|
||||
arch/mips/include/asm/fpu.h | 5 +++--
|
||||
arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
|
||||
4 files changed, 33 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -2586,6 +2586,20 @@ config MIPS_O32_FP64_SUPPORT
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
+config MIPS_FPU_EMULATOR
|
||||
+ bool "MIPS FPU Emulator"
|
||||
+ default y
|
||||
+ help
|
||||
+ This option lets you disable the built-in MIPS FPU (Coprocessor 1)
|
||||
+ emulator, which handles floating-point instructions on processors
|
||||
+ without a hardware FPU. It is generally a good idea to keep the
|
||||
+ emulator built-in, unless you are perfectly sure you have a
|
||||
+ complete soft-float environment. With the emulator disabled, all
|
||||
+ users of float operations will be killed with an illegal instr-
|
||||
+ uction exception.
|
||||
+
|
||||
+ Say Y, please.
|
||||
+
|
||||
config USE_OF
|
||||
bool
|
||||
select OF
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -292,7 +292,7 @@ OBJCOPYFLAGS += --remove-section=.regin
|
||||
head-y := arch/mips/kernel/head.o
|
||||
|
||||
libs-y += arch/mips/lib/
|
||||
-libs-y += arch/mips/math-emu/
|
||||
+libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/
|
||||
|
||||
# See arch/mips/Kbuild for content of core part of the kernel
|
||||
core-y += arch/mips/
|
||||
--- a/arch/mips/include/asm/fpu.h
|
||||
+++ b/arch/mips/include/asm/fpu.h
|
||||
@@ -212,8 +212,10 @@ static inline int init_fpu(void)
|
||||
/* Restore FRE */
|
||||
write_c0_config5(config5);
|
||||
enable_fpu_hazard();
|
||||
- } else
|
||||
+ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
|
||||
fpu_emulator_init_fpu();
|
||||
+ else
|
||||
+ ret = SIGILL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
--- a/arch/mips/include/asm/fpu_emulator.h
|
||||
+++ b/arch/mips/include/asm/fpu_emulator.h
|
||||
@@ -30,6 +30,7 @@
|
||||
#include <asm/local.h>
|
||||
#include <asm/processor.h>
|
||||
|
||||
+#ifdef CONFIG_MIPS_FPU_EMULATOR
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
|
||||
struct mips_fpu_emulator_stats {
|
||||
@@ -65,6 +66,20 @@ extern int do_dsemulret(struct pt_regs *
|
||||
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||
struct mips_fpu_struct *ctx, int has_fpu,
|
||||
void *__user *fault_addr);
|
||||
+#else /* no CONFIG_MIPS_FPU_EMULATOR */
|
||||
+static inline int do_dsemulret(struct pt_regs *xcp)
|
||||
+{
|
||||
+ return 0; /* 0 means error, should never get here anyway */
|
||||
+}
|
||||
+
|
||||
+static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||
+ struct mips_fpu_struct *ctx, int has_fpu,
|
||||
+ void *__user *fault_addr)
|
||||
+{
|
||||
+ return SIGILL; /* we don't speak MIPS FPU */
|
||||
+}
|
||||
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
|
||||
+
|
||||
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);
|
@ -1,352 +0,0 @@
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -90,8 +90,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib --gc-sections
|
||||
+ifdef CONFIG_64BIT
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
+else
|
||||
+KBUILD_AFLAGS_MODULE += -mno-long-calls
|
||||
+KBUILD_CFLAGS_MODULE += -mno-long-calls
|
||||
+endif
|
||||
|
||||
ifndef CONFIG_FUNCTION_TRACER
|
||||
KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
--- a/arch/mips/include/asm/module.h
|
||||
+++ b/arch/mips/include/asm/module.h
|
||||
@@ -11,6 +11,11 @@ struct mod_arch_specific {
|
||||
const struct exception_table_entry *dbe_start;
|
||||
const struct exception_table_entry *dbe_end;
|
||||
struct mips_hi16 *r_mips_hi16_list;
|
||||
+
|
||||
+ void *phys_plt_tbl;
|
||||
+ void *virt_plt_tbl;
|
||||
+ unsigned int phys_plt_offset;
|
||||
+ unsigned int virt_plt_offset;
|
||||
};
|
||||
|
||||
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
|
||||
--- a/arch/mips/kernel/module.c
|
||||
+++ b/arch/mips/kernel/module.c
|
||||
@@ -43,14 +43,221 @@ struct mips_hi16 {
|
||||
static LIST_HEAD(dbe_list);
|
||||
static DEFINE_SPINLOCK(dbe_lock);
|
||||
|
||||
-#ifdef MODULE_START
|
||||
+/*
|
||||
+ * Get the potential max trampolines size required of the init and
|
||||
+ * non-init sections. Only used if we cannot find enough contiguous
|
||||
+ * physically mapped memory to put the module into.
|
||||
+ */
|
||||
+static unsigned int
|
||||
+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
||||
+ const char *secstrings, unsigned int symindex, bool is_init)
|
||||
+{
|
||||
+ unsigned long ret = 0;
|
||||
+ unsigned int i, j;
|
||||
+ Elf_Sym *syms;
|
||||
+
|
||||
+ /* Everything marked ALLOC (this includes the exported symbols) */
|
||||
+ for (i = 1; i < hdr->e_shnum; ++i) {
|
||||
+ unsigned int info = sechdrs[i].sh_info;
|
||||
+
|
||||
+ if (sechdrs[i].sh_type != SHT_REL
|
||||
+ && sechdrs[i].sh_type != SHT_RELA)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Not a valid relocation section? */
|
||||
+ if (info >= hdr->e_shnum)
|
||||
+ continue;
|
||||
+
|
||||
+ /* Don't bother with non-allocated sections */
|
||||
+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
|
||||
+ continue;
|
||||
+
|
||||
+ /* If it's called *.init*, and we're not init, we're
|
||||
+ not interested */
|
||||
+ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
|
||||
+ != is_init)
|
||||
+ continue;
|
||||
+
|
||||
+ syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
|
||||
+ if (sechdrs[i].sh_type == SHT_REL) {
|
||||
+ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
|
||||
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
|
||||
+
|
||||
+ for (j = 0; j < size; ++j) {
|
||||
+ Elf_Sym *sym;
|
||||
+
|
||||
+ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
|
||||
+ continue;
|
||||
+
|
||||
+ sym = syms + ELF_MIPS_R_SYM(rel[j]);
|
||||
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||
+ continue;
|
||||
+
|
||||
+ ret += 4 * sizeof(int);
|
||||
+ }
|
||||
+ } else {
|
||||
+ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
|
||||
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
|
||||
+
|
||||
+ for (j = 0; j < size; ++j) {
|
||||
+ Elf_Sym *sym;
|
||||
+
|
||||
+ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
|
||||
+ continue;
|
||||
+
|
||||
+ sym = syms + ELF_MIPS_R_SYM(rela[j]);
|
||||
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||
+ continue;
|
||||
+
|
||||
+ ret += 4 * sizeof(int);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+#ifndef MODULE_START
|
||||
+static void *alloc_phys(unsigned long size)
|
||||
+{
|
||||
+ unsigned order;
|
||||
+ struct page *page;
|
||||
+ struct page *p;
|
||||
+
|
||||
+ size = PAGE_ALIGN(size);
|
||||
+ order = get_order(size);
|
||||
+
|
||||
+ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
|
||||
+ __GFP_THISNODE, order);
|
||||
+ if (!page)
|
||||
+ return NULL;
|
||||
+
|
||||
+ split_page(page, order);
|
||||
+
|
||||
+ /* mark all pages except for the last one */
|
||||
+ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
|
||||
+ set_bit(PG_owner_priv_1, &p->flags);
|
||||
+
|
||||
+ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
|
||||
+ __free_page(p);
|
||||
+
|
||||
+ return page_address(page);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static void free_phys(void *ptr)
|
||||
+{
|
||||
+ struct page *page;
|
||||
+ bool free;
|
||||
+
|
||||
+ page = virt_to_page(ptr);
|
||||
+ do {
|
||||
+ free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
|
||||
+ __free_page(page);
|
||||
+ page++;
|
||||
+ } while (free);
|
||||
+}
|
||||
+
|
||||
+
|
||||
void *module_alloc(unsigned long size)
|
||||
{
|
||||
+#ifdef MODULE_START
|
||||
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
|
||||
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
|
||||
__builtin_return_address(0));
|
||||
+#else
|
||||
+ void *ptr;
|
||||
+
|
||||
+ if (size == 0)
|
||||
+ return NULL;
|
||||
+
|
||||
+ ptr = alloc_phys(size);
|
||||
+
|
||||
+ /* If we failed to allocate physically contiguous memory,
|
||||
+ * fall back to regular vmalloc. The module loader code will
|
||||
+ * create jump tables to handle long jumps */
|
||||
+ if (!ptr)
|
||||
+ return vmalloc(size);
|
||||
+
|
||||
+ return ptr;
|
||||
+#endif
|
||||
}
|
||||
+
|
||||
+static inline bool is_phys_addr(void *ptr)
|
||||
+{
|
||||
+#ifdef CONFIG_64BIT
|
||||
+ return (KSEGX((unsigned long)ptr) == CKSEG0);
|
||||
+#else
|
||||
+ return (KSEGX(ptr) == KSEG0);
|
||||
#endif
|
||||
+}
|
||||
+
|
||||
+/* Free memory returned from module_alloc */
|
||||
+void module_memfree(void *module_region)
|
||||
+{
|
||||
+ if (is_phys_addr(module_region))
|
||||
+ free_phys(module_region);
|
||||
+ else
|
||||
+ vfree(module_region);
|
||||
+}
|
||||
+
|
||||
+static void *__module_alloc(int size, bool phys)
|
||||
+{
|
||||
+ void *ptr;
|
||||
+
|
||||
+ if (phys)
|
||||
+ ptr = kmalloc(size, GFP_KERNEL);
|
||||
+ else
|
||||
+ ptr = vmalloc(size);
|
||||
+ return ptr;
|
||||
+}
|
||||
+
|
||||
+static void __module_free(void *ptr)
|
||||
+{
|
||||
+ if (is_phys_addr(ptr))
|
||||
+ kfree(ptr);
|
||||
+ else
|
||||
+ vfree(ptr);
|
||||
+}
|
||||
+
|
||||
+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||
+ char *secstrings, struct module *mod)
|
||||
+{
|
||||
+ unsigned int symindex = 0;
|
||||
+ unsigned int core_size, init_size;
|
||||
+ int i;
|
||||
+
|
||||
+ mod->arch.phys_plt_offset = 0;
|
||||
+ mod->arch.virt_plt_offset = 0;
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ mod->arch.virt_plt_tbl = NULL;
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_64BIT))
|
||||
+ return 0;
|
||||
+
|
||||
+ for (i = 1; i < hdr->e_shnum; i++)
|
||||
+ if (sechdrs[i].sh_type == SHT_SYMTAB)
|
||||
+ symindex = i;
|
||||
+
|
||||
+ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
|
||||
+ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
|
||||
+
|
||||
+ if ((core_size + init_size) == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
|
||||
+ if (!mod->arch.phys_plt_tbl)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
|
||||
+ if (!mod->arch.virt_plt_tbl) {
|
||||
+ __module_free(mod->arch.phys_plt_tbl);
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
|
||||
int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
@@ -64,8 +271,39 @@ static int apply_r_mips_32_rel(struct mo
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
|
||||
+ void *start, Elf_Addr v)
|
||||
+{
|
||||
+ unsigned *tramp = start + *plt_offset;
|
||||
+ *plt_offset += 4 * sizeof(int);
|
||||
+
|
||||
+ /* adjust carry for addiu */
|
||||
+ if (v & 0x00008000)
|
||||
+ v += 0x10000;
|
||||
+
|
||||
+ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */
|
||||
+ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */
|
||||
+ tramp[2] = 0x03200008; /* jr t9 */
|
||||
+ tramp[3] = 0x00000000; /* nop */
|
||||
+
|
||||
+ return (Elf_Addr) tramp;
|
||||
+}
|
||||
+
|
||||
+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
|
||||
+{
|
||||
+ if (is_phys_addr(location))
|
||||
+ return add_plt_entry_to(&me->arch.phys_plt_offset,
|
||||
+ me->arch.phys_plt_tbl, v);
|
||||
+ else
|
||||
+ return add_plt_entry_to(&me->arch.virt_plt_offset,
|
||||
+ me->arch.virt_plt_tbl, v);
|
||||
+
|
||||
+}
|
||||
+
|
||||
static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||
{
|
||||
+ u32 ofs = *location & 0x03ffffff;
|
||||
+
|
||||
if (v % 4) {
|
||||
pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
|
||||
me->name);
|
||||
@@ -73,14 +311,17 @@ static int apply_r_mips_26_rel(struct mo
|
||||
}
|
||||
|
||||
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||
- printk(KERN_ERR
|
||||
- "module %s: relocation overflow\n",
|
||||
- me->name);
|
||||
- return -ENOEXEC;
|
||||
+ v = add_plt_entry(me, location, v + (ofs << 2));
|
||||
+ if (!v) {
|
||||
+ printk(KERN_ERR
|
||||
+ "module %s: relocation overflow\n", me->name);
|
||||
+ return -ENOEXEC;
|
||||
+ }
|
||||
+ ofs = 0;
|
||||
}
|
||||
|
||||
*location = (*location & ~0x03ffffff) |
|
||||
- ((*location + (v >> 2)) & 0x03ffffff);
|
||||
+ ((ofs + (v >> 2)) & 0x03ffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -287,9 +528,33 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||
list_add(&me->arch.dbe_list, &dbe_list);
|
||||
spin_unlock_irq(&dbe_lock);
|
||||
}
|
||||
+
|
||||
+ /* Get rid of the fixup trampoline if we're running the module
|
||||
+ * from physically mapped address space */
|
||||
+ if (me->arch.phys_plt_offset == 0) {
|
||||
+ __module_free(me->arch.phys_plt_tbl);
|
||||
+ me->arch.phys_plt_tbl = NULL;
|
||||
+ }
|
||||
+ if (me->arch.virt_plt_offset == 0) {
|
||||
+ __module_free(me->arch.virt_plt_tbl);
|
||||
+ me->arch.virt_plt_tbl = NULL;
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
+void module_arch_freeing_init(struct module *mod)
|
||||
+{
|
||||
+ if (mod->arch.phys_plt_tbl) {
|
||||
+ __module_free(mod->arch.phys_plt_tbl);
|
||||
+ mod->arch.phys_plt_tbl = NULL;
|
||||
+ }
|
||||
+ if (mod->arch.virt_plt_tbl) {
|
||||
+ __module_free(mod->arch.virt_plt_tbl);
|
||||
+ mod->arch.virt_plt_tbl = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void module_arch_cleanup(struct module *mod)
|
||||
{
|
||||
spin_lock_irq(&dbe_lock);
|
@ -1,83 +0,0 @@
|
||||
--- a/arch/mips/include/asm/string.h
|
||||
+++ b/arch/mips/include/asm/string.h
|
||||
@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
|
||||
|
||||
#define __HAVE_ARCH_MEMSET
|
||||
extern void *memset(void *__s, int __c, size_t __count);
|
||||
+#define memset(__s, __c, len) \
|
||||
+({ \
|
||||
+ size_t __len = (len); \
|
||||
+ void *__ret; \
|
||||
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||
+ __ret = memset((__s), (__c), __len); \
|
||||
+ else \
|
||||
+ __ret = __builtin_memset((__s), (__c), __len); \
|
||||
+ __ret; \
|
||||
+})
|
||||
|
||||
#define __HAVE_ARCH_MEMCPY
|
||||
extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
|
||||
+#define memcpy(dst, src, len) \
|
||||
+({ \
|
||||
+ size_t __len = (len); \
|
||||
+ void *__ret; \
|
||||
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||
+ __ret = memcpy((dst), (src), __len); \
|
||||
+ else \
|
||||
+ __ret = __builtin_memcpy((dst), (src), __len); \
|
||||
+ __ret; \
|
||||
+})
|
||||
|
||||
#define __HAVE_ARCH_MEMMOVE
|
||||
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
|
||||
+#define memmove(dst, src, len) \
|
||||
+({ \
|
||||
+ size_t __len = (len); \
|
||||
+ void *__ret; \
|
||||
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||
+ __ret = memmove((dst), (src), __len); \
|
||||
+ else \
|
||||
+ __ret = __builtin_memmove((dst), (src), __len); \
|
||||
+ __ret; \
|
||||
+})
|
||||
+
|
||||
+#define __HAVE_ARCH_MEMCMP
|
||||
+#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
|
||||
|
||||
#endif /* _ASM_STRING_H */
|
||||
--- a/arch/mips/lib/Makefile
|
||||
+++ b/arch/mips/lib/Makefile
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
|
||||
mips-atomic.o strlen_user.o strncpy_user.o \
|
||||
- strnlen_user.o uncached.o
|
||||
+ strnlen_user.o uncached.o memcmp.o
|
||||
|
||||
obj-y += iomap.o
|
||||
obj-$(CONFIG_PCI) += iomap-pci.o
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/lib/memcmp.c
|
||||
@@ -0,0 +1,22 @@
|
||||
+/*
|
||||
+ * copied from linux/lib/string.c
|
||||
+ *
|
||||
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/string.h>
|
||||
+
|
||||
+#undef memcmp
|
||||
+int memcmp(const void *cs, const void *ct, size_t count)
|
||||
+{
|
||||
+ const unsigned char *su1, *su2;
|
||||
+ int res = 0;
|
||||
+
|
||||
+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
|
||||
+ if ((res = *su1 - *su2) != 0)
|
||||
+ break;
|
||||
+ return res;
|
||||
+}
|
||||
+EXPORT_SYMBOL(memcmp);
|
||||
+
|
@ -1,17 +0,0 @@
|
||||
Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
|
||||
stay within the same 256M boundary. This ensures that -mlong-calls is not
|
||||
needed on systems with more than 256M RAM.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@openwrt.org>
|
||||
---
|
||||
--- a/arch/mips/include/asm/mach-generic/spaces.h
|
||||
+++ b/arch/mips/include/asm/mach-generic/spaces.h
|
||||
@@ -44,7 +44,7 @@
|
||||
* Memory above this physical address will be considered highmem.
|
||||
*/
|
||||
#ifndef HIGHMEM_START
|
||||
-#define HIGHMEM_START _AC(0x20000000, UL)
|
||||
+#define HIGHMEM_START _AC(0x10000000, UL)
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_32BIT */
|
@ -1,32 +0,0 @@
|
||||
--- a/arch/mips/mm/cache.c
|
||||
+++ b/arch/mips/mm/cache.c
|
||||
@@ -38,6 +38,7 @@ void (*__flush_cache_vunmap)(void);
|
||||
|
||||
void (*__flush_kernel_vmap_range)(unsigned long vaddr, int size);
|
||||
EXPORT_SYMBOL_GPL(__flush_kernel_vmap_range);
|
||||
+EXPORT_SYMBOL(__flush_cache_all);
|
||||
void (*__invalidate_kernel_vmap_range)(unsigned long vaddr, int size);
|
||||
|
||||
/* MIPS specific cache operations */
|
||||
--- a/fs/fuse/dev.c
|
||||
+++ b/fs/fuse/dev.c
|
||||
@@ -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");
|
||||
@@ -825,6 +828,9 @@ static int fuse_copy_fill(struct fuse_co
|
||||
static int fuse_copy_do(struct fuse_copy_state *cs, void **val, unsigned *size)
|
||||
{
|
||||
unsigned ncpy = min(*size, cs->len);
|
||||
+#ifdef CONFIG_MIPS
|
||||
+ __flush_cache_all();
|
||||
+#endif
|
||||
if (val) {
|
||||
void *pgaddr = kmap_atomic(cs->pg);
|
||||
void *buf = pgaddr + cs->offset;
|
@ -1,13 +0,0 @@
|
||||
--- a/arch/arm/kernel/module.c
|
||||
+++ b/arch/arm/kernel/module.c
|
||||
@@ -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)) {
|
@ -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
|
||||
@@ -203,7 +203,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
|
||||
@@ -45,10 +45,10 @@ BOOTCFLAGS += -I$(obj) -I$(srctree)/$(ob
|
||||
DTC_FLAGS ?= -p 1024
|
||||
|
||||
$(obj)/4xx.o: BOOTCFLAGS += -mcpu=405
|
||||
-$(obj)/ebony.o: BOOTCFLAGS += -mcpu=405
|
||||
+$(obj)/ebony.o: BOOTCFLAGS += -mcpu=440
|
||||
$(obj)/cuboot-hotfoot.o: BOOTCFLAGS += -mcpu=405
|
||||
-$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=405
|
||||
-$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=405
|
||||
+$(obj)/cuboot-taishan.o: BOOTCFLAGS += -mcpu=440
|
||||
+$(obj)/cuboot-katmai.o: BOOTCFLAGS += -mcpu=440
|
||||
$(obj)/cuboot-acadia.o: BOOTCFLAGS += -mcpu=405
|
||||
$(obj)/treeboot-walnut.o: BOOTCFLAGS += -mcpu=405
|
||||
$(obj)/treeboot-iss4xx.o: BOOTCFLAGS += -mcpu=405
|
@ -1,10 +0,0 @@
|
||||
--- a/arch/powerpc/Makefile
|
||||
+++ b/arch/powerpc/Makefile
|
||||
@@ -165,7 +165,6 @@ CPP = $(CC) -E $(KBUILD_CFLAGS)
|
||||
|
||||
CHECKFLAGS += -m$(CONFIG_WORD_SIZE) -D__powerpc__ -D__powerpc$(CONFIG_WORD_SIZE)__
|
||||
|
||||
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
|
||||
|
||||
ifeq ($(CONFIG_476FPE_ERR46),y)
|
||||
KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
|
@ -1,298 +0,0 @@
|
||||
From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
|
||||
From: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Date: Sat, 31 Jan 2015 22:26:03 +0800
|
||||
Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
|
||||
userspace.
|
||||
|
||||
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
---
|
||||
arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
|
||||
arch/mips/kernel/machine_kexec.h | 20 +++++
|
||||
arch/mips/kernel/relocate_kernel.S | 21 +++--
|
||||
3 files changed, 167 insertions(+), 27 deletions(-)
|
||||
create mode 100644 arch/mips/kernel/machine_kexec.h
|
||||
|
||||
--- a/arch/mips/kernel/machine_kexec.c
|
||||
+++ b/arch/mips/kernel/machine_kexec.c
|
||||
@@ -10,45 +10,145 @@
|
||||
#include <linux/mm.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
+#include <asm/bootinfo.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/page.h>
|
||||
-
|
||||
-extern const unsigned char relocate_new_kernel[];
|
||||
-extern const size_t relocate_new_kernel_size;
|
||||
-
|
||||
-extern unsigned long kexec_start_address;
|
||||
-extern unsigned long kexec_indirection_page;
|
||||
+#include <asm/uaccess.h>
|
||||
+#include "machine_kexec.h"
|
||||
|
||||
int (*_machine_kexec_prepare)(struct kimage *) = NULL;
|
||||
void (*_machine_kexec_shutdown)(void) = NULL;
|
||||
void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
|
||||
+
|
||||
#ifdef CONFIG_SMP
|
||||
void (*relocated_kexec_smp_wait) (void *);
|
||||
atomic_t kexec_ready_to_reboot = ATOMIC_INIT(0);
|
||||
#endif
|
||||
|
||||
-int
|
||||
-machine_kexec_prepare(struct kimage *kimage)
|
||||
+static void machine_kexec_print_args(void)
|
||||
{
|
||||
+ unsigned long argc = (int)kexec_args[0];
|
||||
+ int i;
|
||||
+
|
||||
+ pr_info("kexec_args[0] (argc): %lu\n", argc);
|
||||
+ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
|
||||
+ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
|
||||
+ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
|
||||
+
|
||||
+ for (i = 0; i < argc; i++) {
|
||||
+ pr_info("kexec_argv[%d] = %p, %s\n",
|
||||
+ i, kexec_argv[i], kexec_argv[i]);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void machine_kexec_init_argv(struct kimage *image)
|
||||
+{
|
||||
+ void __user *buf = NULL;
|
||||
+ size_t bufsz;
|
||||
+ size_t size;
|
||||
+ int i;
|
||||
+
|
||||
+ bufsz = 0;
|
||||
+ for (i = 0; i < image->nr_segments; i++) {
|
||||
+ struct kexec_segment *seg;
|
||||
+
|
||||
+ seg = &image->segment[i];
|
||||
+ if (seg->bufsz < 6)
|
||||
+ continue;
|
||||
+
|
||||
+ if (strncmp((char *) seg->buf, "kexec ", 6))
|
||||
+ continue;
|
||||
+
|
||||
+ buf = seg->buf;
|
||||
+ bufsz = seg->bufsz;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!buf)
|
||||
+ return;
|
||||
+
|
||||
+ size = KEXEC_COMMAND_LINE_SIZE;
|
||||
+ size = min(size, bufsz);
|
||||
+ if (size < bufsz)
|
||||
+ pr_warn("kexec command line truncated to %zd bytes\n", size);
|
||||
+
|
||||
+ /* Copy to kernel space */
|
||||
+ copy_from_user(kexec_argv_buf, buf, size);
|
||||
+ kexec_argv_buf[size - 1] = 0;
|
||||
+}
|
||||
+
|
||||
+static void machine_kexec_parse_argv(struct kimage *image)
|
||||
+{
|
||||
+ char *reboot_code_buffer;
|
||||
+ int reloc_delta;
|
||||
+ char *ptr;
|
||||
+ int argc;
|
||||
+ int i;
|
||||
+
|
||||
+ ptr = kexec_argv_buf;
|
||||
+ argc = 0;
|
||||
+
|
||||
+ /*
|
||||
+ * convert command line string to array of parameters
|
||||
+ * (as bootloader does).
|
||||
+ */
|
||||
+ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
|
||||
+ if (*ptr == ' ') {
|
||||
+ *ptr++ = '\0';
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ kexec_argv[argc++] = ptr;
|
||||
+ ptr = strchr(ptr, ' ');
|
||||
+ }
|
||||
+
|
||||
+ if (!argc)
|
||||
+ return;
|
||||
+
|
||||
+ kexec_args[0] = argc;
|
||||
+ kexec_args[1] = (unsigned long)kexec_argv;
|
||||
+ kexec_args[2] = 0;
|
||||
+ kexec_args[3] = 0;
|
||||
+
|
||||
+ reboot_code_buffer = page_address(image->control_code_page);
|
||||
+ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
|
||||
+
|
||||
+ kexec_args[1] += reloc_delta;
|
||||
+ for (i = 0; i < argc; i++)
|
||||
+ kexec_argv[i] += reloc_delta;
|
||||
+}
|
||||
+
|
||||
+int machine_kexec_prepare(struct kimage *kimage)
|
||||
+{
|
||||
+ /*
|
||||
+ * Whenever arguments passed from kexec-tools, Init the arguments as
|
||||
+ * the original ones to try avoiding booting failure.
|
||||
+ */
|
||||
+
|
||||
+ kexec_args[0] = fw_arg0;
|
||||
+ kexec_args[1] = fw_arg1;
|
||||
+ kexec_args[2] = fw_arg2;
|
||||
+ kexec_args[3] = fw_arg3;
|
||||
+
|
||||
+ machine_kexec_init_argv(kimage);
|
||||
+ machine_kexec_parse_argv(kimage);
|
||||
+
|
||||
if (_machine_kexec_prepare)
|
||||
return _machine_kexec_prepare(kimage);
|
||||
return 0;
|
||||
}
|
||||
|
||||
-void
|
||||
-machine_kexec_cleanup(struct kimage *kimage)
|
||||
+void machine_kexec_cleanup(struct kimage *kimage)
|
||||
{
|
||||
}
|
||||
|
||||
-void
|
||||
-machine_shutdown(void)
|
||||
+void machine_shutdown(void)
|
||||
{
|
||||
if (_machine_kexec_shutdown)
|
||||
_machine_kexec_shutdown();
|
||||
}
|
||||
|
||||
-void
|
||||
-machine_crash_shutdown(struct pt_regs *regs)
|
||||
+void machine_crash_shutdown(struct pt_regs *regs)
|
||||
{
|
||||
if (_machine_crash_shutdown)
|
||||
_machine_crash_shutdown(regs);
|
||||
@@ -66,10 +166,12 @@ machine_kexec(struct kimage *image)
|
||||
unsigned long *ptr;
|
||||
|
||||
reboot_code_buffer =
|
||||
- (unsigned long)page_address(image->control_code_page);
|
||||
+ (unsigned long)page_address(image->control_code_page);
|
||||
+ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
|
||||
|
||||
kexec_start_address =
|
||||
(unsigned long) phys_to_virt(image->start);
|
||||
+ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
|
||||
|
||||
if (image->type == KEXEC_TYPE_DEFAULT) {
|
||||
kexec_indirection_page =
|
||||
@@ -77,9 +179,19 @@ machine_kexec(struct kimage *image)
|
||||
} else {
|
||||
kexec_indirection_page = (unsigned long)&image->head;
|
||||
}
|
||||
+ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
|
||||
|
||||
- memcpy((void*)reboot_code_buffer, relocate_new_kernel,
|
||||
- relocate_new_kernel_size);
|
||||
+ pr_info("Where is memcpy: %p\n", memcpy);
|
||||
+ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
|
||||
+ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
|
||||
+ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
|
||||
+ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
|
||||
+ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
|
||||
+ KEXEC_RELOCATE_NEW_KERNEL_SIZE);
|
||||
+
|
||||
+ pr_info("Before _print_args().\n");
|
||||
+ machine_kexec_print_args();
|
||||
+ pr_info("Before eval loop.\n");
|
||||
|
||||
/*
|
||||
* The generic kexec code builds a page list with physical
|
||||
@@ -98,15 +210,16 @@ machine_kexec(struct kimage *image)
|
||||
/*
|
||||
* we do not want to be bothered.
|
||||
*/
|
||||
+ pr_info("Before irq_disable.\n");
|
||||
local_irq_disable();
|
||||
|
||||
- printk("Will call new kernel at %08lx\n", image->start);
|
||||
- printk("Bye ...\n");
|
||||
+ pr_info("Will call new kernel at %08lx\n", image->start);
|
||||
+ pr_info("Bye ...\n");
|
||||
__flush_cache_all();
|
||||
#ifdef CONFIG_SMP
|
||||
/* All secondary cpus now may jump to kexec_wait cycle */
|
||||
relocated_kexec_smp_wait = reboot_code_buffer +
|
||||
- (void *)(kexec_smp_wait - relocate_new_kernel);
|
||||
+ (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
|
||||
smp_wmb();
|
||||
atomic_set(&kexec_ready_to_reboot, 1);
|
||||
#endif
|
||||
--- /dev/null
|
||||
+++ b/arch/mips/kernel/machine_kexec.h
|
||||
@@ -0,0 +1,20 @@
|
||||
+#ifndef _MACHINE_KEXEC_H
|
||||
+#define _MACHINE_KEXEC_H
|
||||
+
|
||||
+#ifndef __ASSEMBLY__
|
||||
+extern const unsigned char kexec_relocate_new_kernel[];
|
||||
+extern unsigned long kexec_relocate_new_kernel_end;
|
||||
+extern unsigned long kexec_start_address;
|
||||
+extern unsigned long kexec_indirection_page;
|
||||
+
|
||||
+extern char kexec_argv_buf[];
|
||||
+extern char *kexec_argv[];
|
||||
+
|
||||
+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
|
||||
+#endif /* !__ASSEMBLY__ */
|
||||
+
|
||||
+#define KEXEC_COMMAND_LINE_SIZE 256
|
||||
+#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
|
||||
+#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
|
||||
+
|
||||
+#endif
|
||||
--- a/arch/mips/kernel/relocate_kernel.S
|
||||
+++ b/arch/mips/kernel/relocate_kernel.S
|
||||
@@ -12,8 +12,9 @@
|
||||
#include <asm/mipsregs.h>
|
||||
#include <asm/stackframe.h>
|
||||
#include <asm/addrspace.h>
|
||||
+#include "machine_kexec.h"
|
||||
|
||||
-LEAF(relocate_new_kernel)
|
||||
+LEAF(kexec_relocate_new_kernel)
|
||||
PTR_L a0, arg0
|
||||
PTR_L a1, arg1
|
||||
PTR_L a2, arg2
|
||||
@@ -98,7 +99,7 @@ done:
|
||||
#endif
|
||||
/* jump to kexec_start_address */
|
||||
j s1
|
||||
- END(relocate_new_kernel)
|
||||
+ END(kexec_relocate_new_kernel)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
@@ -184,9 +185,15 @@ kexec_indirection_page:
|
||||
PTR 0
|
||||
.size kexec_indirection_page, PTRSIZE
|
||||
|
||||
-relocate_new_kernel_end:
|
||||
+kexec_argv_buf:
|
||||
+ EXPORT(kexec_argv_buf)
|
||||
+ .skip KEXEC_COMMAND_LINE_SIZE
|
||||
+ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
|
||||
+
|
||||
+kexec_argv:
|
||||
+ EXPORT(kexec_argv)
|
||||
+ .skip KEXEC_ARGV_SIZE
|
||||
+ .size kexec_argv, KEXEC_ARGV_SIZE
|
||||
|
||||
-relocate_new_kernel_size:
|
||||
- EXPORT(relocate_new_kernel_size)
|
||||
- PTR relocate_new_kernel_end - relocate_new_kernel
|
||||
- .size relocate_new_kernel_size, PTRSIZE
|
||||
+kexec_relocate_new_kernel_end:
|
||||
+ EXPORT(kexec_relocate_new_kernel_end)
|
@ -1,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.
|
||||
@@ -546,8 +549,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;
|
||||
@@ -579,21 +584,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:
|
||||
@@ -603,6 +611,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;
|
||||
@@ -626,6 +640,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
|
||||
@@ -655,6 +698,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
|
@ -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
|
||||
@@ -728,6 +728,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);
|
||||
@@ -801,6 +825,38 @@ int parse_mtd_partitions(struct mtd_info
|
||||
return ret;
|
||||
}
|
||||
|
||||
+int parse_mtd_partitions_by_type(struct mtd_info *master,
|
||||
+ enum mtd_parser_type type,
|
||||
+ struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data)
|
||||
+{
|
||||
+ struct mtd_part_parser *prev = NULL;
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ while (1) {
|
||||
+ struct mtd_part_parser *parser;
|
||||
+
|
||||
+ parser = get_partition_parser_by_type(type, prev);
|
||||
+ if (!parser)
|
||||
+ break;
|
||||
+
|
||||
+ ret = (*parser->parse_fn)(master, pparts, data);
|
||||
+
|
||||
+ if (ret > 0) {
|
||||
+ put_partition_parser(parser);
|
||||
+ printk(KERN_NOTICE
|
||||
+ "%d %s partitions found on MTD device %s\n",
|
||||
+ ret, parser->name, master->name);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ prev = parser;
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
|
||||
+
|
||||
int mtd_is_partition(const struct mtd_info *mtd)
|
||||
{
|
||||
struct mtd_part *part;
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -68,12 +68,17 @@ struct mtd_part_parser_data {
|
||||
* Functions dealing with the various ways of partitioning the space
|
||||
*/
|
||||
|
||||
+enum mtd_parser_type {
|
||||
+ MTD_PARSER_TYPE_DEVICE = 0,
|
||||
+};
|
||||
+
|
||||
struct mtd_part_parser {
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
const char *name;
|
||||
int (*parse_fn)(struct mtd_info *, struct mtd_partition **,
|
||||
struct mtd_part_parser_data *);
|
||||
+ enum mtd_parser_type type;
|
||||
};
|
||||
|
||||
extern void register_mtd_parser(struct mtd_part_parser *parser);
|
||||
@@ -87,4 +92,9 @@ uint64_t mtd_get_device_size(const struc
|
||||
extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||
const char *name, int offset, int size);
|
||||
|
||||
+int parse_mtd_partitions_by_type(struct mtd_info *master,
|
||||
+ enum mtd_parser_type type,
|
||||
+ struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data);
|
||||
+
|
||||
#endif
|
@ -1,72 +0,0 @@
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -640,6 +640,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
|
||||
@@ -648,6 +679,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,
|
||||
@@ -662,6 +694,12 @@ static void mtd_partition_split(struct m
|
||||
if (rootfs_found)
|
||||
return;
|
||||
|
||||
+ if (!strcmp(part->mtd.name, "rootfs")) {
|
||||
+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
|
||||
+
|
||||
+ rootfs_found = 1;
|
||||
+ }
|
||||
+
|
||||
if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||
config_enabled(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||
split_firmware(master, part);
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -70,6 +70,8 @@ struct mtd_part_parser_data {
|
||||
|
||||
enum mtd_parser_type {
|
||||
MTD_PARSER_TYPE_DEVICE = 0,
|
||||
+ MTD_PARSER_TYPE_ROOTFS,
|
||||
+ MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
||||
struct mtd_part_parser {
|
@ -1,22 +0,0 @@
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
|
||||
depends on MTD_SPLIT_FIRMWARE
|
||||
default "firmware"
|
||||
|
||||
+source "drivers/mtd/mtdsplit/Kconfig"
|
||||
+
|
||||
endmenu
|
||||
|
||||
config MTD_TESTS
|
||||
--- a/drivers/mtd/Makefile
|
||||
+++ b/drivers/mtd/Makefile
|
||||
@@ -6,6 +6,8 @@
|
||||
obj-$(CONFIG_MTD) += mtd.o
|
||||
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
|
||||
|
||||
+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
|
||||
+
|
||||
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
|
||||
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
|
||||
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
|
@ -1,101 +0,0 @@
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -444,14 +444,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;
|
||||
@@ -671,6 +669,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
|
||||
@@ -912,6 +921,24 @@ int mtd_is_partition(const struct mtd_in
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_is_partition);
|
||||
|
||||
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (!mtd_is_partition(mtd))
|
||||
+ return (struct mtd_info *)mtd;
|
||||
+
|
||||
+ return PART(mtd)->master;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(mtdpart_get_master);
|
||||
+
|
||||
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (!mtd_is_partition(mtd))
|
||||
+ return 0;
|
||||
+
|
||||
+ return PART(mtd)->offset;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(mtdpart_get_offset);
|
||||
+
|
||||
/* Returns the size of the entire flash chip */
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd)
|
||||
{
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -90,6 +90,8 @@ int mtd_is_partition(const struct mtd_in
|
||||
int mtd_add_partition(struct mtd_info *master, const char *name,
|
||||
long long offset, long long length);
|
||||
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
|
||||
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||
extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||
const char *name, int offset, int size);
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -334,6 +334,24 @@ static inline uint32_t mtd_mod_by_eb(uin
|
||||
return do_div(sz, mtd->erasesize);
|
||||
}
|
||||
|
||||
+static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (mtd_mod_by_eb(sz, mtd) == 0)
|
||||
+ return sz;
|
||||
+
|
||||
+ /* Round up to next erase block */
|
||||
+ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
|
||||
+}
|
||||
+
|
||||
+static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (mtd_mod_by_eb(sz, mtd) == 0)
|
||||
+ return sz;
|
||||
+
|
||||
+ /* Round down to the start of the current erase block */
|
||||
+ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
|
||||
+}
|
||||
+
|
||||
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
|
||||
{
|
||||
if (mtd->writesize_shift)
|
@ -1,70 +0,0 @@
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -27,6 +27,11 @@ config MTD_SPLIT_FIRMWARE_NAME
|
||||
depends on MTD_SPLIT_FIRMWARE
|
||||
default "firmware"
|
||||
|
||||
+config MTD_UIMAGE_SPLIT
|
||||
+ bool "Enable split support for firmware partitions containing a uImage"
|
||||
+ depends on MTD_SPLIT_FIRMWARE
|
||||
+ default y
|
||||
+
|
||||
source "drivers/mtd/mtdsplit/Kconfig"
|
||||
|
||||
endmenu
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -680,6 +680,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
|
||||
@@ -688,7 +719,14 @@ mtd_pad_erasesize(struct mtd_info *mtd,
|
||||
|
||||
static void split_firmware(struct mtd_info *master, struct mtd_part *part)
|
||||
{
|
||||
- run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
|
||||
+ if (ret > 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (config_enabled(CONFIG_MTD_UIMAGE_SPLIT))
|
||||
+ split_uimage(master, part);
|
||||
}
|
||||
|
||||
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
|
@ -1,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
|
||||
@@ -680,6 +680,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)
|
||||
@@ -742,7 +783,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;
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -35,6 +35,7 @@
|
||||
* Note: writeable partitions require their size and offset be
|
||||
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
|
||||
*/
|
||||
+struct mtd_info;
|
||||
|
||||
struct mtd_partition {
|
||||
const char *name; /* identifier string */
|
||||
@@ -50,7 +51,6 @@ struct mtd_partition {
|
||||
#define MTDPART_SIZ_FULL (0)
|
||||
|
||||
|
||||
-struct mtd_info;
|
||||
struct device_node;
|
||||
|
||||
/**
|
@ -1,142 +0,0 @@
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -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);
|
||||
@@ -233,13 +235,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;
|
||||
}
|
||||
|
||||
@@ -247,7 +297,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;
|
||||
@@ -513,17 +581,20 @@ static struct mtd_part *allocate_partiti
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||
mtd_mod_by_eb(slave->offset, &slave->mtd)) {
|
||||
/* Doesn't start on a boundary of major erase size */
|
||||
- /* FIXME: Let it be writable if it is on a boundary of
|
||||
- * _minor_ erase size though */
|
||||
- slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
|
||||
- part->name);
|
||||
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||
+ if (((u32) slave->mtd.size) > master->erasesize)
|
||||
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
+ else
|
||||
+ slave->mtd.erasesize = slave->mtd.size;
|
||||
}
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||
- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
|
||||
- slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
|
||||
- part->name);
|
||||
+ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
|
||||
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||
+
|
||||
+ if ((u32) slave->mtd.size > master->erasesize)
|
||||
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
+ else
|
||||
+ slave->mtd.erasesize = slave->mtd.size;
|
||||
}
|
||||
|
||||
slave->mtd.ecclayout = master->ecclayout;
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -55,6 +55,10 @@ struct erase_info {
|
||||
u_long priv;
|
||||
u_char state;
|
||||
struct erase_info *next;
|
||||
+
|
||||
+ u8 *erase_buf;
|
||||
+ u32 erase_buf_ofs;
|
||||
+ bool partial_start;
|
||||
};
|
||||
|
||||
struct mtd_erase_region_info {
|
@ -1,18 +0,0 @@
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -334,7 +334,14 @@ static int part_lock(struct mtd_info *mt
|
||||
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
struct mtd_part *part = PART(mtd);
|
||||
- return part->master->_unlock(part->master, ofs + part->offset, len);
|
||||
+
|
||||
+ ofs += part->offset;
|
||||
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
|
||||
+ /* round up len to next erasesize and round down offset to prev block */
|
||||
+ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
|
||||
+ ofs &= ~(part->master->erasesize - 1);
|
||||
+ }
|
||||
+ return part->master->_unlock(part->master, ofs, len);
|
||||
}
|
||||
|
||||
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
@ -1,30 +0,0 @@
|
||||
--- a/drivers/mtd/redboot.c
|
||||
+++ b/drivers/mtd/redboot.c
|
||||
@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
|
||||
#endif
|
||||
names += strlen(names)+1;
|
||||
|
||||
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
|
||||
- i++;
|
||||
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||
- parts[i].name = nullname;
|
||||
- }
|
||||
+ if (!strcmp(parts[i].name, "rootfs")) {
|
||||
+ parts[i].size = fl->next->img->flash_base;
|
||||
+ parts[i].size &= ~(master->erasesize - 1);
|
||||
+ parts[i].size -= parts[i].offset;
|
||||
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||
+ nrparts--;
|
||||
+ } else {
|
||||
+ i++;
|
||||
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||
+ parts[i].name = nullname;
|
||||
#endif
|
||||
+ }
|
||||
+ }
|
||||
tmp_fl = fl;
|
||||
fl = fl->next;
|
||||
kfree(tmp_fl);
|
@ -1,35 +0,0 @@
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -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 || ATH25 || ATH79
|
||||
+ ---help---
|
||||
+ MyLoader is a bootloader which allows the user to define partitions
|
||||
+ in flash devices, by putting a table in the second erase block
|
||||
+ on the device, similar to a partition table. This table gives the
|
||||
+ offsets and lengths of the user defined partitions.
|
||||
+
|
||||
+ If you need code which can detect and parse these tables, and
|
||||
+ register MTD 'partitions' corresponding to each image detected,
|
||||
+ enable this option.
|
||||
+
|
||||
+ You will still need the parsing functions to be called by the driver
|
||||
+ for your particular device. It won't happen automatically.
|
||||
+
|
||||
comment "User Modules And Translation Layers"
|
||||
|
||||
#
|
||||
--- a/drivers/mtd/Makefile
|
||||
+++ b/drivers/mtd/Makefile
|
||||
@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
|
||||
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
|
||||
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
|
||||
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
|
||||
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
|
||||
|
||||
# 'Users' - code which presents functionality to userspace.
|
||||
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
|
@ -1,34 +0,0 @@
|
||||
From 841e59ba3e496d86ca5f069204d5e5c1ad43c01d Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Tue, 27 Jan 2015 22:29:21 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxpart: support for Xiaomi specific board_data
|
||||
partition
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
drivers/mtd/bcm47xxpart.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/bcm47xxpart.c
|
||||
@@ -33,6 +33,7 @@
|
||||
/* Magics */
|
||||
#define BOARD_DATA_MAGIC 0x5246504D /* MPFR */
|
||||
#define BOARD_DATA_MAGIC2 0xBD0D0BBD
|
||||
+#define BOARD_DATA_XIAOMI_MAGIC 0x474D4442 /* GMDB */
|
||||
#define CFE_MAGIC 0x43464531 /* 1EFC */
|
||||
#define FACTORY_MAGIC 0x59544346 /* FCTY */
|
||||
#define NVRAM_HEADER 0x48534C46 /* FLSH */
|
||||
@@ -262,7 +263,8 @@ static int bcm47xxpart_parse(struct mtd_
|
||||
}
|
||||
|
||||
/* Some devices (ex. WNDR3700v3) don't have a standard 'MPFR' */
|
||||
- if (buf[0x000 / 4] == BOARD_DATA_MAGIC2) {
|
||||
+ if (buf[0x000 / 4] == BOARD_DATA_MAGIC2 ||
|
||||
+ le32_to_cpu(buf[0x000 / 4]) == BOARD_DATA_XIAOMI_MAGIC) {
|
||||
bcm47xxpart_add_part(&parts[curr_part++], "board_data",
|
||||
offset, MTD_WRITEABLE);
|
||||
continue;
|
@ -1,42 +0,0 @@
|
||||
From fd54aa583296f9adfb1f519affbc10ba521eb809 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Date: Wed, 28 Jan 2015 22:14:41 +0100
|
||||
Subject: [PATCH] mtd: bcm47xxpart: detect T_Meter partition
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It can be found on many Netgear devices. It consists of many 0x30 blocks
|
||||
starting with 4D 54.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
drivers/mtd/bcm47xxpart.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/bcm47xxpart.c
|
||||
@@ -39,6 +39,7 @@
|
||||
#define NVRAM_HEADER 0x48534C46 /* FLSH */
|
||||
#define POT_MAGIC1 0x54544f50 /* POTT */
|
||||
#define POT_MAGIC2 0x504f /* OP */
|
||||
+#define T_METER_MAGIC 0x4D540000 /* MT */
|
||||
#define ML_MAGIC1 0x39685a42
|
||||
#define ML_MAGIC2 0x26594131
|
||||
#define TRX_MAGIC 0x30524448
|
||||
@@ -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) {
|
@ -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>
|
||||
@@ -209,11 +210,12 @@ static void block2mtd_free_device(struct
|
||||
}
|
||||
|
||||
|
||||
-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)
|
||||
@@ -257,13 +259,16 @@ static struct block2mtd_dev *add_device(
|
||||
|
||||
/* Setup the MTD structure */
|
||||
/* make the name contain the block device in */
|
||||
- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
|
||||
+ if (!mtdname)
|
||||
+ mtdname = devname;
|
||||
+ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
|
||||
if (!name)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
+ strcpy(name, mtdname);
|
||||
dev->mtd.name = name;
|
||||
|
||||
- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
|
||||
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
|
||||
dev->mtd.erasesize = erase_size;
|
||||
dev->mtd.writesize = 1;
|
||||
dev->mtd.writebufsize = PAGE_SIZE;
|
||||
@@ -276,15 +281,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 err_destroy_mutex;
|
||||
}
|
||||
list_add(&dev->list, &blkmtd_device_list);
|
||||
pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
|
||||
dev->mtd.index,
|
||||
- dev->mtd.name + strlen("block2mtd: "),
|
||||
- dev->mtd.erasesize >> 10, dev->mtd.erasesize);
|
||||
+ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
|
||||
return dev;
|
||||
|
||||
err_destroy_mutex:
|
||||
@@ -353,9 +361,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;
|
||||
@@ -368,7 +376,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) {
|
||||
@@ -394,8 +402,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;
|
||||
}
|
||||
@@ -429,7 +439,7 @@ static int block2mtd_setup(const char *v
|
||||
|
||||
|
||||
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
|
||||
-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
|
||||
+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
|
||||
|
||||
static int __init block2mtd_init(void)
|
||||
{
|
@ -1,110 +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>
|
||||
@@ -210,13 +211,16 @@ static void block2mtd_free_device(struct
|
||||
}
|
||||
|
||||
|
||||
-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;
|
||||
+#ifndef MODULE
|
||||
+ int i;
|
||||
+#endif
|
||||
|
||||
if (!devname)
|
||||
return NULL;
|
||||
@@ -227,15 +231,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
|
||||
|
||||
@@ -361,11 +370,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)) {
|
||||
@@ -376,7 +386,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) {
|
||||
@@ -405,7 +415,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;
|
||||
}
|
||||
@@ -439,7 +452,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)
|
||||
{
|
||||
@@ -474,7 +487,7 @@ static void block2mtd_exit(void)
|
||||
}
|
||||
|
||||
|
||||
-module_init(block2mtd_init);
|
||||
+late_initcall(block2mtd_init);
|
||||
module_exit(block2mtd_exit);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
@ -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
|
||||
@@ -865,6 +865,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;
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
--- a/drivers/mtd/nand/nand_ecc.c
|
||||
+++ b/drivers/mtd/nand/nand_ecc.c
|
||||
@@ -507,7 +507,7 @@ int __nand_correct_data(unsigned char *b
|
||||
return 1; /* error in ECC data; no action needed */
|
||||
|
||||
pr_err("%s: uncorrectable ECC error\n", __func__);
|
||||
- return -1;
|
||||
+ return -EBADMSG;
|
||||
}
|
||||
EXPORT_SYMBOL(__nand_correct_data);
|
||||
|
@ -1,11 +0,0 @@
|
||||
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
@@ -809,7 +809,7 @@ static int get_chip(struct map_info *map
|
||||
return 0;
|
||||
|
||||
case FL_ERASING:
|
||||
- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
|
||||
+ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
|
||||
!(mode == FL_READY || mode == FL_POINT ||
|
||||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
|
||||
goto sleep;
|
@ -1,18 +0,0 @@
|
||||
From: George Kashperko <george@znau.edu.ua>
|
||||
|
||||
Issue map read after Write Buffer Load command to ensure chip is ready
|
||||
to receive data.
|
||||
Signed-off-by: George Kashperko <george@znau.edu.ua>
|
||||
---
|
||||
drivers/mtd/chips/cfi_cmdset_0002.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
@@ -1830,6 +1830,7 @@ static int __xipram do_write_buffer(stru
|
||||
|
||||
/* Write Buffer Load */
|
||||
map_write(map, CMD(0x25), cmd_adr);
|
||||
+ (void) map_read(map, cmd_adr);
|
||||
|
||||
chip->state = FL_WRITING_TO_BUFFER;
|
||||
|
@ -1,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/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -649,6 +649,7 @@ static const struct spi_device_id spi_no
|
||||
{ "m25px80", INFO(0x207114, 0, 64 * 1024, 16, 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) },
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user