kernel: split patches folder up into backport, pending and hack folders
* properly format/comment all patches * merge debloat patches * merge Kconfig patches * merge swconfig patches * merge hotplug patches * drop 200-fix_localversion.patch - upstream * drop 222-arm_zimage_none.patch - unused * drop 252-mv_cesa_depends.patch - no longer required * drop 410-mtd-move-forward-declaration-of-struct-mtd_info.patch - unused * drop 661-fq_codel_keep_dropped_stats.patch - outdated * drop 702-phy_add_aneg_done_function.patch - upstream * drop 840-rtc7301.patch - unused * drop 841-rtc_pt7c4338.patch - upstream * drop 921-use_preinit_as_init.patch - unused * drop spio-gpio-old and gpio-mmc - unused Signed-off-by: John Crispin <john@phrozen.org>
This commit is contained in:
@@ -0,0 +1,30 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: MIPS: fix cache flushing for highmem pages
|
||||
|
||||
Most cache flush ops were no-op for highmem pages. This led to nasty
|
||||
segfaults and (in the case of page_address(page) == NULL) kernel
|
||||
crashes.
|
||||
|
||||
Fix this by always flushing highmem pages using kmap/kunmap_atomic
|
||||
around the actual cache flush. This might be a bit inefficient, but at
|
||||
least it's stable.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/mips/mm/cache.c
|
||||
+++ b/arch/mips/mm/cache.c
|
||||
@@ -115,6 +115,13 @@ void __flush_anon_page(struct page *page
|
||||
{
|
||||
unsigned long addr = (unsigned long) page_address(page);
|
||||
|
||||
+ if (PageHighMem(page)) {
|
||||
+ addr = (unsigned long)kmap_atomic(page);
|
||||
+ flush_data_cache_page(addr);
|
||||
+ __kunmap_atomic((void *)addr);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (pages_do_alias(addr, vmaddr)) {
|
||||
if (page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||
void *kaddr;
|
||||
@@ -0,0 +1,79 @@
|
||||
From: Florian Fainelli <florian@openwrt.org>
|
||||
Subject: 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
|
||||
@@ -651,7 +651,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
|
||||
@@ -638,7 +638,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;
|
||||
@@ -1008,7 +1008,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
|
||||
@@ -259,6 +259,8 @@ static int ehci_platform_probe(struct pl
|
||||
hcd->has_tt = 1;
|
||||
if (pdata->reset_on_resume)
|
||||
priv->reset_on_resume = true;
|
||||
+ if (pdata->ignore_oc)
|
||||
+ ehci->ignore_oc = 1;
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
if (ehci->big_endian_mmio) {
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -230,6 +230,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);
|
||||
@@ -0,0 +1,82 @@
|
||||
From: Tobias Wolf <dev-NTEO@vplace.de>
|
||||
Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation
|
||||
|
||||
An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
|
||||
kernel beyond version 4.3 resulting in:
|
||||
|
||||
BUG: Bad page state in process swapper pfn:086ac
|
||||
|
||||
bisect resulted in:
|
||||
|
||||
a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
|
||||
commit a1c34a3bf00af2cede839879502e12dc68491ad5
|
||||
Author: Laura Abbott <laura@labbott.name>
|
||||
Date: Thu Nov 5 18:48:46 2015 -0800
|
||||
|
||||
mm: Don't offset memmap for flatmem
|
||||
|
||||
Srinivas Kandagatla reported bad page messages when trying to remove the
|
||||
bottom 2MB on an ARM based IFC6410 board
|
||||
|
||||
BUG: Bad page state in process swapper pfn:fffa8
|
||||
page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0
|
||||
flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
|
||||
page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
|
||||
bad because of flags:
|
||||
flags: 0x200041(locked|active|mlocked)
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
|
||||
#816
|
||||
Hardware name: Qualcomm (Flattened Device Tree)
|
||||
unwind_backtrace
|
||||
show_stack
|
||||
dump_stack
|
||||
bad_page
|
||||
free_pages_prepare
|
||||
free_hot_cold_page
|
||||
__free_pages
|
||||
free_highmem_page
|
||||
mem_init
|
||||
start_kernel
|
||||
Disabling lock debugging due to kernel taint
|
||||
[...]
|
||||
:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
|
||||
0a8156f848733dfa21e16c196dfb6c0a76290709 M mm
|
||||
|
||||
This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
|
||||
page_to_pfn anymore.
|
||||
|
||||
The following output was generated with two hacked in printk statements:
|
||||
|
||||
printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
|
||||
(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||
printk("after %p\n", mem_map);
|
||||
|
||||
Output:
|
||||
|
||||
[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280
|
||||
[ 0.000000] after 8851b280
|
||||
|
||||
As seen in the first line mem_map with subtraction of offset does not equal the
|
||||
mem_map after subtraction of ARCH_PFN_OFFSET.
|
||||
|
||||
After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
|
||||
previously calculated offset is zero for the named platform it is able to boot
|
||||
4.4 and 4.9-rc7 again.
|
||||
|
||||
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||
---
|
||||
|
||||
--- a/mm/page_alloc.c
|
||||
+++ b/mm/page_alloc.c
|
||||
@@ -5905,7 +5905,7 @@ static void __ref alloc_node_mem_map(str
|
||||
mem_map = NODE_DATA(0)->node_mem_map;
|
||||
#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
- mem_map -= offset;
|
||||
+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||
#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
From: Giuseppe Lippolis <giu.lippolis@gmail.com>
|
||||
Subject: Add the linux,spidev compatible in spidev Several device in ramips have this binding in the dts
|
||||
|
||||
Signed-off-by: Giuseppe Lippolis <giu.lippolis@gmail.com>
|
||||
---
|
||||
drivers/spi/spidev.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
|
||||
index 2e05046f866b..09d03763f39b 100644
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -696,6 +696,7 @@ static struct class *spidev_class;
|
||||
static const struct of_device_id spidev_dt_ids[] = {
|
||||
{ .compatible = "rohm,dh2228fv" },
|
||||
{ .compatible = "lineartechnology,ltc2488" },
|
||||
+ { .compatible = "siliconlabs,si3210" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: spi: use gpio_set_value_cansleep for setting chipselect GPIO
|
||||
|
||||
Sleeping is safe inside spi_transfer_one_message, and some GPIO chips
|
||||
need to sleep for setting values
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/spi/spi.c
|
||||
+++ b/drivers/spi/spi.c
|
||||
@@ -698,7 +698,7 @@ static void spi_set_cs(struct spi_device
|
||||
enable = !enable;
|
||||
|
||||
if (gpio_is_valid(spi->cs_gpio))
|
||||
- gpio_set_value(spi->cs_gpio, !enable);
|
||||
+ gpio_set_value_cansleep(spi->cs_gpio, !enable);
|
||||
else if (spi->master->set_cs)
|
||||
spi->master->set_cs(spi, !enable);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support
|
||||
|
||||
It is required for renames on overlayfs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -756,6 +756,24 @@ 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,
|
||||
unsigned int flags)
|
||||
@@ -766,7 +784,7 @@ static int jffs2_rename (struct inode *o
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
- if (flags & ~RENAME_NOREPLACE)
|
||||
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||
return -EINVAL;
|
||||
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
@@ -832,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 */
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: jffs2: add RENAME_EXCHANGE support
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -781,18 +781,31 @@ static int jffs2_rename (struct inode *o
|
||||
int ret;
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
|
||||
struct jffs2_inode_info *victim_f = NULL;
|
||||
+ struct inode *fst_inode = d_inode(old_dentry);
|
||||
+ struct inode *snd_inode = d_inode(new_dentry);
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
|
||||
return -EINVAL;
|
||||
|
||||
+ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
|
||||
+ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
|
||||
+ inc_nlink(new_dir_i);
|
||||
+ drop_nlink(old_dir_i);
|
||||
+ }
|
||||
+ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
|
||||
+ drop_nlink(new_dir_i);
|
||||
+ inc_nlink(old_dir_i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* 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
|
||||
* needs to do that for itself.
|
||||
*/
|
||||
- if (d_really_is_positive(new_dentry)) {
|
||||
+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
|
||||
victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
|
||||
if (d_is_dir(new_dentry)) {
|
||||
struct jffs2_full_dirent *fd;
|
||||
@@ -827,7 +840,7 @@ static int jffs2_rename (struct inode *o
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (victim_f) {
|
||||
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
|
||||
/* There was a victim. Kill it off nicely */
|
||||
if (d_is_dir(new_dentry))
|
||||
clear_nlink(d_inode(new_dentry));
|
||||
@@ -853,6 +866,12 @@ static int jffs2_rename (struct inode *o
|
||||
if (flags & RENAME_WHITEOUT)
|
||||
/* Replace with whiteout */
|
||||
ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||
+ else if (flags & RENAME_EXCHANGE)
|
||||
+ /* Replace the original */
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
+ d_inode(new_dentry)->i_ino, type,
|
||||
+ old_dentry->d_name.name, old_dentry->d_name.len,
|
||||
+ now);
|
||||
else
|
||||
/* Unlink the original */
|
||||
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
@@ -884,7 +903,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);
|
||||
@@ -0,0 +1,43 @@
|
||||
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@nbd.name>
|
||||
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -233,7 +233,8 @@ static int br_handle_local_finish(struct
|
||||
{
|
||||
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
|
||||
- __br_handle_local_finish(skb);
|
||||
+ if (p->state != BR_STATE_DISABLED)
|
||||
+ __br_handle_local_finish(skb);
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
|
||||
br_pass_frame_up(skb);
|
||||
@@ -316,6 +317,15 @@ 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;
|
||||
+
|
||||
+ NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
|
||||
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
+ br_handle_local_finish);
|
||||
+ break;
|
||||
+
|
||||
case BR_STATE_FORWARDING:
|
||||
rhook = rcu_dereference(br_should_route_hook);
|
||||
if (rhook) {
|
||||
@@ -0,0 +1,181 @@
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Subject: mtd: part: add generic parsing of linux,part-probe
|
||||
|
||||
This moves the linux,part-probe device tree parsing code from
|
||||
physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
|
||||
providing a reference to their device tree node in struct
|
||||
mtd_part_parser_data.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
Documentation/devicetree/bindings/mtd/nand.txt | 16 +++++++++
|
||||
drivers/mtd/maps/physmap_of.c | 46 +-------------------------
|
||||
drivers/mtd/mtdpart.c | 45 +++++++++++++++++++++++++
|
||||
3 files changed, 62 insertions(+), 45 deletions(-)
|
||||
|
||||
--- a/Documentation/devicetree/bindings/mtd/nand.txt
|
||||
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
|
||||
@@ -44,6 +44,22 @@ Optional NAND chip properties:
|
||||
used by the upper layers, and you want to make your NAND
|
||||
as reliable as possible.
|
||||
|
||||
+- linux,part-probe: list of name as strings of the partition parser
|
||||
+ which should be used to parse the partition table.
|
||||
+ They will be tried in the specified ordering and
|
||||
+ the next one will be used if the previous one
|
||||
+ failed.
|
||||
+
|
||||
+ Example: linux,part-probe = "cmdlinepart", "ofpart";
|
||||
+
|
||||
+ This is also the default value, which will be used
|
||||
+ if this attribute is not specified. It could be
|
||||
+ that the flash driver in use overwrote the default
|
||||
+ value and uses some other default.
|
||||
+
|
||||
+ Possible values are: bcm47xxpart, afs, ar7part,
|
||||
+ ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
|
||||
+
|
||||
The ECC strength and ECC step size properties define the correction capability
|
||||
of a controller. Together, they say a controller can correct "{strength} bit
|
||||
errors per {size} bytes".
|
||||
--- a/drivers/mtd/maps/physmap_of.c
|
||||
+++ b/drivers/mtd/maps/physmap_of.c
|
||||
@@ -113,47 +113,9 @@ static struct mtd_info *obsolete_probe(s
|
||||
static const char * const part_probe_types_def[] = {
|
||||
"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
|
||||
|
||||
-static const char * const *of_get_probes(struct device_node *dp)
|
||||
-{
|
||||
- const char *cp;
|
||||
- int cplen;
|
||||
- unsigned int l;
|
||||
- unsigned int count;
|
||||
- const char **res;
|
||||
-
|
||||
- cp = of_get_property(dp, "linux,part-probe", &cplen);
|
||||
- if (cp == NULL)
|
||||
- return part_probe_types_def;
|
||||
-
|
||||
- count = 0;
|
||||
- for (l = 0; l != cplen; l++)
|
||||
- if (cp[l] == 0)
|
||||
- count++;
|
||||
-
|
||||
- res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
|
||||
- if (!res)
|
||||
- return NULL;
|
||||
- count = 0;
|
||||
- while (cplen > 0) {
|
||||
- res[count] = cp;
|
||||
- l = strlen(cp) + 1;
|
||||
- cp += l;
|
||||
- cplen -= l;
|
||||
- count++;
|
||||
- }
|
||||
- return res;
|
||||
-}
|
||||
-
|
||||
-static void of_free_probes(const char * const *probes)
|
||||
-{
|
||||
- if (probes != part_probe_types_def)
|
||||
- kfree(probes);
|
||||
-}
|
||||
-
|
||||
static const struct of_device_id of_flash_match[];
|
||||
static int of_flash_probe(struct platform_device *dev)
|
||||
{
|
||||
- const char * const *part_probe_types;
|
||||
const struct of_device_id *match;
|
||||
struct device_node *dp = dev->dev.of_node;
|
||||
struct resource res;
|
||||
@@ -317,14 +279,8 @@ static int of_flash_probe(struct platfor
|
||||
|
||||
info->cmtd->dev.parent = &dev->dev;
|
||||
mtd_set_of_node(info->cmtd, dp);
|
||||
- part_probe_types = of_get_probes(dp);
|
||||
- if (!part_probe_types) {
|
||||
- err = -ENOMEM;
|
||||
- goto err_out;
|
||||
- }
|
||||
- mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
|
||||
+ mtd_device_parse_register(info->cmtd, part_probe_types_def, NULL,
|
||||
NULL, 0);
|
||||
- of_free_probes(part_probe_types);
|
||||
|
||||
kfree(mtd_list);
|
||||
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
+#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "mtdcore.h"
|
||||
@@ -855,6 +856,42 @@ void deregister_mtd_parser(struct mtd_pa
|
||||
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
|
||||
|
||||
/*
|
||||
+ * Parses the linux,part-probe device tree property.
|
||||
+ * When a non null value is returned it has to be freed with kfree() by
|
||||
+ * the caller.
|
||||
+ */
|
||||
+static const char * const *of_get_probes(struct device_node *dp)
|
||||
+{
|
||||
+ const char *cp;
|
||||
+ int cplen;
|
||||
+ unsigned int l;
|
||||
+ unsigned int count;
|
||||
+ const char **res;
|
||||
+
|
||||
+ cp = of_get_property(dp, "linux,part-probe", &cplen);
|
||||
+ if (cp == NULL)
|
||||
+ return NULL;
|
||||
+
|
||||
+ count = 0;
|
||||
+ for (l = 0; l != cplen; l++)
|
||||
+ if (cp[l] == 0)
|
||||
+ count++;
|
||||
+
|
||||
+ res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
|
||||
+ if (!res)
|
||||
+ return NULL;
|
||||
+ count = 0;
|
||||
+ while (cplen > 0) {
|
||||
+ res[count] = cp;
|
||||
+ l = strlen(cp) + 1;
|
||||
+ cp += l;
|
||||
+ cplen -= l;
|
||||
+ count++;
|
||||
+ }
|
||||
+ return res;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
|
||||
* are changing this array!
|
||||
*/
|
||||
@@ -912,6 +949,13 @@ int parse_mtd_partitions(struct mtd_info
|
||||
{
|
||||
struct mtd_part_parser *parser;
|
||||
int ret, err = 0;
|
||||
+ const char *const *types_of = NULL;
|
||||
+
|
||||
+ if (mtd_get_of_node(master)) {
|
||||
+ types_of = of_get_probes(mtd_get_of_node(master));
|
||||
+ if (types_of != NULL)
|
||||
+ types = types_of;
|
||||
+ }
|
||||
|
||||
if (!types)
|
||||
types = default_mtd_part_types;
|
||||
@@ -937,6 +981,7 @@ int parse_mtd_partitions(struct mtd_info
|
||||
if (ret < 0 && !err)
|
||||
err = ret;
|
||||
}
|
||||
+ kfree(types_of);
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Mathias Kresin <dev@kresin.me>
|
||||
Subject: MIPS: PCI: add controllers before the specified head
|
||||
|
||||
With commit 23dac14d058f ("MIPS: PCI: Use struct list_head lists") new
|
||||
controllers are added after the specified head where they were added
|
||||
before the specified head previously.
|
||||
|
||||
Use list_add_tail to restore the former order.
|
||||
|
||||
This patches fixes the following PCI error on lantiq:
|
||||
|
||||
pci 0000:01:00.0: BAR 0: error updating (0x1c000004 != 0x000000)
|
||||
|
||||
Fixes: 23dac14d058f ("MIPS: PCI: Use struct list_head lists")
|
||||
Signed-off-by: Mathias Kresin <dev@kresin.me>
|
||||
---
|
||||
arch/mips/pci/pci-legacy.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/mips/pci/pci-legacy.c
|
||||
+++ b/arch/mips/pci/pci-legacy.c
|
||||
@@ -190,7 +190,7 @@ void register_pci_controller(struct pci_
|
||||
}
|
||||
|
||||
INIT_LIST_HEAD(&hose->list);
|
||||
- list_add(&hose->list, &controllers);
|
||||
+ list_add_tail(&hose->list, &controllers);
|
||||
|
||||
/*
|
||||
* Do not panic here but later - this might happen before console init.
|
||||
@@ -0,0 +1,70 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: net: phy: at803x: add support for AT8032
|
||||
|
||||
Like AT8030, this PHY needs the GPIO reset workaround
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -62,6 +62,7 @@
|
||||
|
||||
#define ATH8030_PHY_ID 0x004dd076
|
||||
#define ATH8031_PHY_ID 0x004dd074
|
||||
+#define ATH8032_PHY_ID 0x004dd023
|
||||
#define ATH8035_PHY_ID 0x004dd072
|
||||
|
||||
MODULE_DESCRIPTION("Atheros 803x PHY driver");
|
||||
@@ -259,7 +260,8 @@ static int at803x_probe(struct phy_devic
|
||||
if (!priv)
|
||||
return -ENOMEM;
|
||||
|
||||
- if (phydev->drv->phy_id != ATH8030_PHY_ID)
|
||||
+ if (phydev->drv->phy_id != ATH8030_PHY_ID &&
|
||||
+ phydev->drv->phy_id != ATH8032_PHY_ID)
|
||||
goto does_not_require_reset_workaround;
|
||||
|
||||
gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||
@@ -335,7 +337,7 @@ static void at803x_link_change_notify(st
|
||||
struct at803x_priv *priv = phydev->priv;
|
||||
|
||||
/*
|
||||
- * Conduct a hardware reset for AT8030 every time a link loss is
|
||||
+ * Conduct a hardware reset for AT8030/2 every time a link loss is
|
||||
* signalled. This is necessary to circumvent a hardware bug that
|
||||
* occurs when the cable is unplugged while TX packets are pending
|
||||
* in the FIFO. In such cases, the FIFO enters an error mode it
|
||||
@@ -447,6 +449,24 @@ static struct phy_driver at803x_driver[]
|
||||
.aneg_done = at803x_aneg_done,
|
||||
.ack_interrupt = &at803x_ack_interrupt,
|
||||
.config_intr = &at803x_config_intr,
|
||||
+}, {
|
||||
+ /* ATHEROS 8032 */
|
||||
+ .phy_id = ATH8032_PHY_ID,
|
||||
+ .name = "Atheros 8032 ethernet",
|
||||
+ .phy_id_mask = 0xffffffef,
|
||||
+ .probe = at803x_probe,
|
||||
+ .config_init = at803x_config_init,
|
||||
+ .link_change_notify = at803x_link_change_notify,
|
||||
+ .set_wol = at803x_set_wol,
|
||||
+ .get_wol = at803x_get_wol,
|
||||
+ .suspend = at803x_suspend,
|
||||
+ .resume = at803x_resume,
|
||||
+ .features = PHY_BASIC_FEATURES,
|
||||
+ .flags = PHY_HAS_INTERRUPT,
|
||||
+ .config_aneg = genphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = at803x_ack_interrupt,
|
||||
+ .config_intr = at803x_config_intr,
|
||||
} };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@@ -454,6 +474,7 @@ module_phy_driver(at803x_driver);
|
||||
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
|
||||
{ ATH8030_PHY_ID, 0xffffffef },
|
||||
{ ATH8031_PHY_ID, 0xffffffef },
|
||||
+ { ATH8032_PHY_ID, 0xffffffef },
|
||||
{ ATH8035_PHY_ID, 0xffffffef },
|
||||
{ }
|
||||
};
|
||||
@@ -0,0 +1,37 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: Upgrade to Linux 2.6.19
|
||||
|
||||
- Includes large parts of the patch from #1021 by dpalffy
|
||||
- Includes RB532 NAND driver changes by n0-1
|
||||
|
||||
[john@phrozen.org: feix will add this to his upstream queue]
|
||||
|
||||
lede-commit: bff468813f78f81e36ebb2a3f4354de7365e640f
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
Makefile | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/Makefile b/Makefile
|
||||
index 598494bc9a4b..1f02ac9b571a 100644
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -637,12 +637,12 @@ KBUILD_CFLAGS += $(call cc-option,-fdata-sections,)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
|
||||
+KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) $(EXTRA_OPTIMIZATION)
|
||||
else
|
||||
ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||
-KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,)
|
||||
+KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,) $(EXTRA_OPTIMIZATION)
|
||||
else
|
||||
-KBUILD_CFLAGS += -O2
|
||||
+KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
|
||||
endif
|
||||
endif
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
130
target/linux/generic/pending-4.9/203-kallsyms_uncompressed.patch
Normal file
130
target/linux/generic/pending-4.9/203-kallsyms_uncompressed.patch
Normal file
@@ -0,0 +1,130 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx
|
||||
|
||||
[john@phrozen.org: added to my upstream queue 30.12.2016]
|
||||
lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
init/Kconfig | 11 +++++++++++
|
||||
kernel/kallsyms.c | 8 ++++++++
|
||||
scripts/kallsyms.c | 12 ++++++++++++
|
||||
scripts/link-vmlinux.sh | 4 ++++
|
||||
4 files changed, 35 insertions(+)
|
||||
|
||||
diff --git a/init/Kconfig b/init/Kconfig
|
||||
index 34407f15e6d3..9063c81b9665 100644
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1370,6 +1370,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
|
||||
|
||||
diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c
|
||||
index fafd1a3ef0da..abe49579212f 100644
|
||||
--- a/kernel/kallsyms.c
|
||||
+++ b/kernel/kallsyms.c
|
||||
@@ -113,6 +113,11 @@ static unsigned int kallsyms_expand_symbol(unsigned int off,
|
||||
* 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++;
|
||||
@@ -145,6 +150,9 @@ static unsigned int kallsyms_expand_symbol(unsigned int off,
|
||||
*/
|
||||
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.
|
||||
diff --git a/scripts/kallsyms.c b/scripts/kallsyms.c
|
||||
index 1f22a186c18c..e7f0f19e39a9 100644
|
||||
--- a/scripts/kallsyms.c
|
||||
+++ b/scripts/kallsyms.c
|
||||
@@ -61,6 +61,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 int base_relative = 0;
|
||||
@@ -446,6 +447,9 @@ static void write_src(void)
|
||||
|
||||
free(markers);
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return;
|
||||
+
|
||||
output_label("kallsyms_token_table");
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -504,6 +508,9 @@ static void *find_token(unsigned char *str, int len, unsigned char *token)
|
||||
{
|
||||
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];
|
||||
@@ -576,6 +583,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--) {
|
||||
@@ -764,6 +774,8 @@ int main(int argc, char **argv)
|
||||
symbol_prefix_char = *p;
|
||||
} else if (strcmp(argv[i], "--base-relative") == 0)
|
||||
base_relative = 1;
|
||||
+ else if (strcmp(argv[i], "--uncompressed") == 0)
|
||||
+ uncompressed = 1;
|
||||
else
|
||||
usage();
|
||||
}
|
||||
diff --git a/scripts/link-vmlinux.sh b/scripts/link-vmlinux.sh
|
||||
index f742c65108b9..6aabf1d71bb6 100755
|
||||
--- a/scripts/link-vmlinux.sh
|
||||
+++ b/scripts/link-vmlinux.sh
|
||||
@@ -136,6 +136,10 @@ kallsyms()
|
||||
kallsymopt="${kallsymopt} --base-relative"
|
||||
fi
|
||||
|
||||
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
|
||||
+ kallsymopt="${kallsymopt} --uncompressed"
|
||||
+ fi
|
||||
+
|
||||
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
||||
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries
|
||||
|
||||
[john@phrozen.org: felix will add this to his upstream queue]
|
||||
|
||||
lede-commit 53827cdc824556cda910b23ce5030c363b8f1461
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
lib/vsprintf.c | 15 +++++++++++----
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
|
||||
index 0967771d8f7f..5d27eae49198 100644
|
||||
--- a/lib/vsprintf.c
|
||||
+++ b/lib/vsprintf.c
|
||||
@@ -669,8 +669,10 @@ char *symbol_string(char *buf, char *end, void *ptr,
|
||||
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')
|
||||
@@ -684,11 +686,16 @@ char *symbol_string(char *buf, char *end, void *ptr,
|
||||
sprint_symbol(sym, value);
|
||||
else
|
||||
sprint_symbol_no_offset(sym, value);
|
||||
-
|
||||
- return string(buf, end, sym, spec);
|
||||
#else
|
||||
- return special_hex_number(buf, end, value, sizeof(void *));
|
||||
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
|
||||
+
|
||||
+ mod = __module_address(value);
|
||||
+ if (mod)
|
||||
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
|
||||
+ mod->name, mod->core_layout.base,
|
||||
+ mod->core_layout.size);
|
||||
#endif
|
||||
+ return string(buf, end, sym, spec);
|
||||
}
|
||||
|
||||
static noinline_for_stack
|
||||
--
|
||||
2.11.0
|
||||
|
||||
28
target/linux/generic/pending-4.9/206-mips-disable-vdso.patch
Normal file
28
target/linux/generic/pending-4.9/206-mips-disable-vdso.patch
Normal file
@@ -0,0 +1,28 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: disable MIPS VDSO by default until the cache issues have been resolved
|
||||
|
||||
lede-commit: 1185e645a773c86aa88cf04d0e2911dc62eb43f5
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/vdso/Makefile | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/arch/mips/vdso/Makefile b/arch/mips/vdso/Makefile
|
||||
index c3dc12a8b7d9..28f66e3bb2c3 100644
|
||||
--- a/arch/mips/vdso/Makefile
|
||||
+++ b/arch/mips/vdso/Makefile
|
||||
@@ -28,9 +28,9 @@ aflags-vdso := $(ccflags-vdso) \
|
||||
ifndef CONFIG_CPU_MIPSR6
|
||||
ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
|
||||
$(warning MIPS VDSO requires binutils >= 2.25)
|
||||
- obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
|
||||
- ccflags-vdso += -DDISABLE_MIPS_VDSO
|
||||
endif
|
||||
+ obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
|
||||
+ ccflags-vdso += -DDISABLE_MIPS_VDSO
|
||||
endif
|
||||
|
||||
# VDSO linker flags.
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: usr: sanitize deps_initramfs list
|
||||
|
||||
If any filename in the intramfs dependency
|
||||
list contains a colon, that causes a kernel
|
||||
build error like this:
|
||||
|
||||
/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop.
|
||||
make[5]: *** [usr] Error 2
|
||||
|
||||
Fix it by removing such filenames from the
|
||||
deps_initramfs list.
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
usr/Makefile | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/usr/Makefile b/usr/Makefile
|
||||
index e767f019accf..17328d3c11cc 100644
|
||||
--- a/usr/Makefile
|
||||
+++ b/usr/Makefile
|
||||
@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data.cpio.d),)
|
||||
include $(obj)/.initramfs_data.cpio.d
|
||||
endif
|
||||
|
||||
+deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
|
||||
+
|
||||
quiet_cmd_initfs = GEN $@
|
||||
cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
|
||||
|
||||
@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initramfs_data.cpio.bz2 \
|
||||
initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \
|
||||
initramfs_data.cpio
|
||||
# do not try to update files included in initramfs
|
||||
-$(deps_initramfs): ;
|
||||
+$(deps_initramfs_sane): ;
|
||||
|
||||
-$(deps_initramfs): klibcdirs
|
||||
+$(deps_initramfs_sane): klibcdirs
|
||||
# We rebuild initramfs_data.cpio if:
|
||||
# 1) Any included file is newer then initramfs_data.cpio
|
||||
# 2) There are changes in which files are included (added or deleted)
|
||||
# 3) If gen_init_cpio are newer than initramfs_data.cpio
|
||||
# 4) arguments to gen_initramfs.sh changes
|
||||
-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
|
||||
+$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
|
||||
$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d
|
||||
$(call if_changed,initfs)
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From: Imre Kaloz <kaloz@openwrt.org>
|
||||
Subject: [PATCH] hack: net: wireless: make the wl12xx glue code available with
|
||||
compat-wireless, too
|
||||
|
||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||
---
|
||||
drivers/net/wireless/ti/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/net/wireless/ti/Kconfig b/drivers/net/wireless/ti/Kconfig
|
||||
index 92fbd6597e34..3b1f951cacf7 100644
|
||||
--- a/drivers/net/wireless/ti/Kconfig
|
||||
+++ b/drivers/net/wireless/ti/Kconfig
|
||||
@@ -19,7 +19,7 @@ source "drivers/net/wireless/ti/wlcore/Kconfig"
|
||||
|
||||
config WILINK_PLATFORM_DATA
|
||||
bool "TI WiLink platform data"
|
||||
- depends on WLCORE_SDIO || WL1251_SDIO
|
||||
+ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
|
||||
default y
|
||||
---help---
|
||||
Small platform data bit needed to pass data to the sdio modules.
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Subject: 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
|
||||
@@ -0,0 +1,105 @@
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Subject: 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 net/if.h header. */
|
||||
-#if defined(_NET_IF_H) && defined(__USE_MISC)
|
||||
+/* Coordinate with libc net/if.h header. */
|
||||
+#if defined(_NET_IF_H) && (!defined(__GLIBC__) || defined(__USE_MISC))
|
||||
|
||||
-/* 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_IF_IFCONF 0
|
||||
@@ -65,7 +65,11 @@
|
||||
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
|
||||
/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
|
||||
#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
|
||||
+#ifdef __GLIBC__
|
||||
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
|
||||
+#else
|
||||
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 0
|
||||
+#endif
|
||||
#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
|
||||
|
||||
#else /* _NET_IF_H */
|
||||
@@ -85,10 +89,10 @@
|
||||
|
||||
#endif /* _NET_IF_H */
|
||||
|
||||
-/* 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
|
||||
@@ -102,7 +106,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
|
||||
@@ -117,7 +121,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
|
||||
@@ -127,7 +131,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
|
||||
@@ -168,7 +172,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 if.h */
|
||||
#define __UAPI_DEF_IF_IFCONF 1
|
||||
@@ -208,6 +212,6 @@
|
||||
/* Definitions for xattr.h */
|
||||
#define __UAPI_DEF_XATTR 1
|
||||
|
||||
-#endif /* __GLIBC__ */
|
||||
+#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* _UAPI_LIBC_COMPAT_H */
|
||||
@@ -0,0 +1,65 @@
|
||||
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||
Subject: 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
|
||||
@@ -138,11 +139,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
|
||||
@@ -89,6 +89,14 @@
|
||||
|
||||
#endif /* _NET_IF_H */
|
||||
|
||||
+/* 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)
|
||||
|
||||
@@ -184,6 +192,9 @@
|
||||
/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
|
||||
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
|
||||
|
||||
+/* 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
|
||||
@@ -0,0 +1,40 @@
|
||||
From: Mark Miller <mark@mirell.org>
|
||||
Subject: mips: expose CONFIG_BOOT_RAW
|
||||
|
||||
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
|
||||
@@ -1065,9 +1065,6 @@ config FW_ARC
|
||||
config ARCH_MAY_HAVE_PC_FDC
|
||||
bool
|
||||
|
||||
-config BOOT_RAW
|
||||
- bool
|
||||
-
|
||||
config CEVT_BCM1480
|
||||
bool
|
||||
|
||||
@@ -2964,6 +2961,18 @@ choice
|
||||
bool "Extend builtin kernel arguments with bootloader arguments"
|
||||
endchoice
|
||||
|
||||
+config BOOT_RAW
|
||||
+ bool "Enable the kernel to be executed from the load address"
|
||||
+ default n
|
||||
+ help
|
||||
+ Allow the kernel to be executed from the load address for
|
||||
+ bootloaders which cannot read the ELF format. This places
|
||||
+ a jump to start_kernel at the load address.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
+
|
||||
+
|
||||
endmenu
|
||||
|
||||
config LOCKDEP_SUPPORT
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: mips: use -mno-branch-likely for kernel and userspace
|
||||
|
||||
saves ~11k kernel size after lzma and ~12k squashfs size in the
|
||||
|
||||
lede-commit: 41a039f46450ffae9483d6216422098669da2900
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/Makefile | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
|
||||
index 1a6bac7b076f..5b656d9a1bbe 100644
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -90,7 +90,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz
|
||||
# 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
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
--
|
||||
2.11.0
|
||||
|
||||
137
target/linux/generic/pending-4.9/304-mips_disable_fpu.patch
Normal file
137
target/linux/generic/pending-4.9/304-mips_disable_fpu.patch
Normal file
@@ -0,0 +1,137 @@
|
||||
From: Manuel Lauss <manuel.lauss@gmail.com>
|
||||
Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
|
||||
|
||||
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
|
||||
@@ -2892,6 +2892,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
|
||||
@@ -287,7 +287,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
|
||||
@@ -227,8 +227,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 {
|
||||
@@ -63,6 +64,16 @@ do { \
|
||||
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 fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||
+ struct mips_fpu_struct *ctx, int has_fpu,
|
||||
+ void *__user *fault_addr)
|
||||
+{
|
||||
+ *fault_addr = NULL;
|
||||
+ return SIGILL; /* we don't speak MIPS FPU */
|
||||
+}
|
||||
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
|
||||
+
|
||||
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
|
||||
struct task_struct *tsk);
|
||||
int process_fpemu_return(int sig, void __user *fault_addr,
|
||||
--- a/arch/mips/include/asm/dsemul.h
|
||||
+++ b/arch/mips/include/asm/dsemul.h
|
||||
@@ -41,6 +41,7 @@ struct task_struct;
|
||||
extern int mips_dsemul(struct pt_regs *regs, mips_instruction ir,
|
||||
unsigned long branch_pc, unsigned long cont_pc);
|
||||
|
||||
+#ifdef CONFIG_MIPS_FPU_EMULATOR
|
||||
/**
|
||||
* do_dsemulret() - Return from a delay slot 'emulation' frame
|
||||
* @xcp: User thread register context.
|
||||
@@ -88,5 +89,27 @@ extern bool dsemul_thread_rollback(struc
|
||||
* before @mm is freed in order to avoid memory leaks.
|
||||
*/
|
||||
extern void dsemul_mm_cleanup(struct mm_struct *mm);
|
||||
+#else
|
||||
+static inline bool do_dsemulret(struct pt_regs *xcp)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static inline bool dsemul_thread_cleanup(struct task_struct *tsk)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static inline bool dsemul_thread_rollback(struct pt_regs *regs)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static inline void dsemul_mm_cleanup(struct mm_struct *mm)
|
||||
+{
|
||||
+
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
|
||||
#endif /* __MIPS_ASM_DSEMUL_H__ */
|
||||
374
target/linux/generic/pending-4.9/305-mips_module_reloc.patch
Normal file
374
target/linux/generic/pending-4.9/305-mips_module_reloc.patch
Normal file
@@ -0,0 +1,374 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: mips: replace -mlong-calls with -mno-long-calls to make function calls faster in kernel modules to achieve this, try to
|
||||
|
||||
lede-commit: 3b3d64743ba2a874df9d70cd19e242205b0a788c
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/Makefile | 5 +
|
||||
arch/mips/include/asm/module.h | 5 +
|
||||
arch/mips/kernel/module.c | 279 ++++++++++++++++++++++++++++++++++++++++-
|
||||
3 files changed, 284 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
|
||||
index 48dc1a9c3e42..77bf5db20d65 100644
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -93,8 +93,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlinuz
|
||||
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||
+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
|
||||
|
||||
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||
LDFLAGS_vmlinux += --emit-relocs
|
||||
diff --git a/arch/mips/include/asm/module.h b/arch/mips/include/asm/module.h
|
||||
index 702c273e67a9..1d4f3b37cefe 100644
|
||||
--- 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. */
|
||||
diff --git a/arch/mips/kernel/module.c b/arch/mips/kernel/module.c
|
||||
index 94627a3a6a0d..947981a9aa72 100644
|
||||
--- a/arch/mips/kernel/module.c
|
||||
+++ b/arch/mips/kernel/module.c
|
||||
@@ -44,14 +44,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)
|
||||
{
|
||||
@@ -65,8 +272,39 @@ static int apply_r_mips_32_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||
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);
|
||||
@@ -74,13 +312,17 @@ static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||
}
|
||||
|
||||
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||
- pr_err("module %s: relocation overflow\n",
|
||||
- me->name);
|
||||
- return -ENOEXEC;
|
||||
+ v = add_plt_entry(me, location, v + (ofs << 2));
|
||||
+ if (!v) {
|
||||
+ pr_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;
|
||||
}
|
||||
@@ -349,9 +591,36 @@ 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->state == MODULE_STATE_LIVE)
|
||||
+ return;
|
||||
+
|
||||
+ 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);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: [PATCH] mips: allow the compiler to optimize memset, memcmp, memcpy for better performance and (in some instances) smaller code
|
||||
|
||||
lede-commit: 07e59c7bc7f375f792ec9734be42fe4fa391a8bb
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/boot/compressed/Makefile | 3 ++-
|
||||
arch/mips/include/asm/string.h | 38 ++++++++++++++++++++++++++++++++++++++
|
||||
arch/mips/lib/Makefile | 2 +-
|
||||
arch/mips/lib/memcmp.c | 22 ++++++++++++++++++++++
|
||||
4 files changed, 63 insertions(+), 2 deletions(-)
|
||||
create mode 100644 arch/mips/lib/memcmp.c
|
||||
|
||||
diff --git a/arch/mips/boot/compressed/Makefile b/arch/mips/boot/compressed/Makefile
|
||||
index 90aca95fe314..3cd3b391ef49 100644
|
||||
--- a/arch/mips/boot/compressed/Makefile
|
||||
+++ b/arch/mips/boot/compressed/Makefile
|
||||
@@ -23,7 +23,8 @@ KBUILD_CFLAGS := $(shell echo $(KBUILD_CFLAGS) | sed -e "s/-pg//")
|
||||
KBUILD_CFLAGS := $(filter-out -fstack-protector, $(KBUILD_CFLAGS))
|
||||
|
||||
KBUILD_CFLAGS := $(LINUXINCLUDE) $(KBUILD_CFLAGS) -D__KERNEL__ \
|
||||
- -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull"
|
||||
+ -DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) -D"VMLINUX_LOAD_ADDRESS_ULL=$(VMLINUX_LOAD_ADDRESS)ull" \
|
||||
+ -D__ZBOOT__
|
||||
|
||||
KBUILD_AFLAGS := $(LINUXINCLUDE) $(KBUILD_AFLAGS) -D__ASSEMBLY__ \
|
||||
-DBOOT_HEAP_SIZE=$(BOOT_HEAP_SIZE) \
|
||||
diff --git a/arch/mips/include/asm/string.h b/arch/mips/include/asm/string.h
|
||||
index 29030cb398ee..7b737f9b6d58 100644
|
||||
--- a/arch/mips/include/asm/string.h
|
||||
+++ b/arch/mips/include/asm/string.h
|
||||
@@ -140,4 +140,42 @@ extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
|
||||
#define __HAVE_ARCH_MEMMOVE
|
||||
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
|
||||
|
||||
+#ifndef __ZBOOT__
|
||||
+#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 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 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
|
||||
+
|
||||
#endif /* _ASM_STRING_H */
|
||||
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
|
||||
index 0344e575f522..33a0211e954a 100644
|
||||
--- 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
|
||||
diff --git a/arch/mips/lib/memcmp.c b/arch/mips/lib/memcmp.c
|
||||
new file mode 100644
|
||||
index 000000000000..35ef1646286e
|
||||
--- /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);
|
||||
+
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: adjust mips highmem offset to avoid the need for -mlong-calls on systems with >256M RAM
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/include/asm/mach-generic/spaces.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/mips/include/asm/mach-generic/spaces.h b/arch/mips/include/asm/mach-generic/spaces.h
|
||||
index 952b0fdfda0e..fbb4e4cd4537 100644
|
||||
--- a/arch/mips/include/asm/mach-generic/spaces.h
|
||||
+++ b/arch/mips/include/asm/mach-generic/spaces.h
|
||||
@@ -46,7 +46,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 */
|
||||
--
|
||||
2.11.0
|
||||
|
||||
27
target/linux/generic/pending-4.9/308-mips32r2_tune.patch
Normal file
27
target/linux/generic/pending-4.9/308-mips32r2_tune.patch
Normal file
@@ -0,0 +1,27 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add -mtune=34kc to MIPS CFLAGS when building for mips32r2
|
||||
|
||||
This provides a good tradeoff across at least 24Kc-74Kc, while also
|
||||
producing smaller code.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/mips/Makefile | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/mips/Makefile b/arch/mips/Makefile
|
||||
index 77bf5db20d65..1ac83e281f90 100644
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -148,7 +148,7 @@ cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||
-Wa,-mips32 -Wa,--trap
|
||||
-cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||
+cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2 -mtune=34kc,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||
-Wa,-mips32r2 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: fix errors in unresolved weak symbols on arm
|
||||
|
||||
lede-commit: 570699d4838a907c3ef9f2819bf19eb72997b32f
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
arch/arm/kernel/module.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
|
||||
index 4f14b5ce6535..4b4b0461663f 100644
|
||||
--- a/arch/arm/kernel/module.c
|
||||
+++ b/arch/arm/kernel/module.c
|
||||
@@ -88,6 +88,10 @@ apply_relocate(Elf32_Shdr *sechdrs, const char *strtab, unsigned int symindex,
|
||||
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)) {
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,269 @@
|
||||
From: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Subject: 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,14 +10,11 @@
|
||||
#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;
|
||||
@@ -28,9 +25,115 @@ atomic_t kexec_ready_to_reboot = ATOMIC_
|
||||
void (*_crash_smp_send_stop)(void) = NULL;
|
||||
#endif
|
||||
|
||||
+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;
|
||||
@@ -67,10 +170,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 =
|
||||
@@ -78,9 +183,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
|
||||
@@ -99,15 +214,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)
|
||||
@@ -0,0 +1,80 @@
|
||||
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Subject: openwrt: arc - add OWRTDTB section
|
||||
|
||||
This change allows OpenWRT to patch resulting kernel binary with
|
||||
external .dtb.
|
||||
|
||||
That allows us to re-use exactky the same vmlinux on different boards
|
||||
given its ARC core configurations match (at least cache line sizes etc).
|
||||
|
||||
""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
|
||||
.dtb right after it, keeping the string in place.
|
||||
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
---
|
||||
arch/arc/kernel/head.S | 10 ++++++++++
|
||||
arch/arc/kernel/setup.c | 4 +++-
|
||||
arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
|
||||
3 files changed, 26 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arc/kernel/head.S
|
||||
+++ b/arch/arc/kernel/head.S
|
||||
@@ -49,6 +49,16 @@
|
||||
1:
|
||||
.endm
|
||||
|
||||
+; Here "patch-dtb" will embed external .dtb
|
||||
+; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
|
||||
+; and pastes .dtb right after it, hense the string precedes
|
||||
+; __image_dtb symbol.
|
||||
+ .section .owrt, "aw",@progbits
|
||||
+ .ascii "OWRTDTB:"
|
||||
+ENTRY(__image_dtb)
|
||||
+ .fill 0x4000
|
||||
+END(__image_dtb)
|
||||
+
|
||||
.section .init.text, "ax",@progbits
|
||||
|
||||
;----------------------------------------------------------------
|
||||
--- a/arch/arc/kernel/setup.c
|
||||
+++ b/arch/arc/kernel/setup.c
|
||||
@@ -388,6 +388,8 @@ static inline int is_kernel(unsigned lon
|
||||
return 0;
|
||||
}
|
||||
|
||||
+extern struct boot_param_header __image_dtb;
|
||||
+
|
||||
void __init setup_arch(char **cmdline_p)
|
||||
{
|
||||
#ifdef CONFIG_ARC_UBOOT_SUPPORT
|
||||
@@ -401,7 +403,7 @@ void __init setup_arch(char **cmdline_p)
|
||||
#endif
|
||||
{
|
||||
/* No, so try the embedded one */
|
||||
- machine_desc = setup_machine_fdt(__dtb_start);
|
||||
+ machine_desc = setup_machine_fdt(&__image_dtb);
|
||||
if (!machine_desc)
|
||||
panic("Embedded DT invalid\n");
|
||||
|
||||
--- a/arch/arc/kernel/vmlinux.lds.S
|
||||
+++ b/arch/arc/kernel/vmlinux.lds.S
|
||||
@@ -30,6 +30,19 @@ SECTIONS
|
||||
|
||||
. = CONFIG_LINUX_LINK_BASE;
|
||||
|
||||
+ /*
|
||||
+ * In OpenWRT we want to patch built binary embedding .dtb of choice.
|
||||
+ * This is implemented with "patch-dtb" utility which searches for
|
||||
+ * "OWRTDTB:" string in first 16k of image and if it is found
|
||||
+ * copies .dtb right after mentioned string.
|
||||
+ *
|
||||
+ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
|
||||
+ */
|
||||
+ .owrt : {
|
||||
+ *(.owrt)
|
||||
+ . = ALIGN(PAGE_SIZE);
|
||||
+ }
|
||||
+
|
||||
_int_vec_base_lds = .;
|
||||
.vector : {
|
||||
*(.vector)
|
||||
@@ -0,0 +1,24 @@
|
||||
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Subject: arc: enable unaligned access in kernel mode
|
||||
|
||||
This enables misaligned access handling even in kernel mode.
|
||||
Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
|
||||
here and there and to cope with that without fixing stuff in the drivers
|
||||
we're just gracefully handling it on ARC.
|
||||
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
---
|
||||
arch/arc/kernel/unaligned.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arc/kernel/unaligned.c
|
||||
+++ b/arch/arc/kernel/unaligned.c
|
||||
@@ -206,7 +206,7 @@ int misaligned_fixup(unsigned long addre
|
||||
char buf[TASK_COMM_LEN];
|
||||
|
||||
/* handle user mode only and only if enabled by sysadmin */
|
||||
- if (!user_mode(regs) || !unaligned_enabled)
|
||||
+ if (!unaligned_enabled)
|
||||
return 1;
|
||||
|
||||
if (no_unaligned_warning) {
|
||||
@@ -0,0 +1,132 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: make rootfs split/detection more generic - patch can be moved to generic-2.6 after testing on other platforms
|
||||
|
||||
lede-commit: 328e660b31f0937d52c5ae3d6e7029409918a9df
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/Kconfig | 17 +++++++++++++++++
|
||||
drivers/mtd/mtdpart.c | 35 +++++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/partitions.h | 2 ++
|
||||
3 files changed, 54 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
|
||||
index 5a2d71729b9a..f5ac04e288eb 100644
|
||||
--- 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
|
||||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||||
index dd86b430e46e..33d152d1876a 100644
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -29,10 +29,12 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
+#include <linux/magic.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/err.h>
|
||||
|
||||
#include "mtdcore.h"
|
||||
+#include "mtdsplit/mtdsplit.h"
|
||||
|
||||
/* Our partition linked list */
|
||||
static LIST_HEAD(mtd_partitions);
|
||||
@@ -52,6 +54,8 @@ 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.
|
||||
@@ -678,6 +682,7 @@ int mtd_add_partition(struct mtd_info *parent, const char *name,
|
||||
mutex_unlock(&mtd_partitions_mutex);
|
||||
|
||||
add_mtd_device(&new->mtd);
|
||||
+ mtd_partition_split(parent, new);
|
||||
|
||||
mtd_add_partition_attrs(new);
|
||||
|
||||
@@ -756,6 +761,35 @@ int mtd_del_partition(struct mtd_info *mtd, int partno)
|
||||
}
|
||||
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) &&
|
||||
+ IS_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
|
||||
@@ -787,6 +821,7 @@ int add_mtd_partitions(struct mtd_info *master,
|
||||
mutex_unlock(&mtd_partitions_mutex);
|
||||
|
||||
add_mtd_device(&slave->mtd);
|
||||
+ mtd_partition_split(master, slave);
|
||||
mtd_add_partition_attrs(slave);
|
||||
if (parts[i].types)
|
||||
mtd_parse_part(slave, parts[i].types);
|
||||
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
|
||||
index c4beb70dacbd..320a791290c5 100644
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -109,5 +109,7 @@ 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);
|
||||
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
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: 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
|
||||
@@ -1036,6 +1036,62 @@ void mtd_part_parser_cleanup(struct mtd_
|
||||
}
|
||||
}
|
||||
|
||||
+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)
|
||||
+ mtd_part_parser_put(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;
|
||||
+}
|
||||
+
|
||||
+int parse_mtd_partitions_by_type(struct mtd_info *master,
|
||||
+ enum mtd_parser_type type,
|
||||
+ const 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) {
|
||||
+ mtd_part_parser_put(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,11 +68,14 @@ struct mtd_part_parser_data {
|
||||
unsigned long origin;
|
||||
};
|
||||
|
||||
-
|
||||
/*
|
||||
* 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;
|
||||
@@ -80,6 +83,7 @@ struct mtd_part_parser {
|
||||
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
|
||||
struct mtd_part_parser_data *);
|
||||
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
|
||||
+ enum mtd_parser_type type;
|
||||
};
|
||||
|
||||
/* Container for passing around a set of parsed partitions */
|
||||
@@ -112,4 +116,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,
|
||||
+ const struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data);
|
||||
+
|
||||
#endif
|
||||
@@ -0,0 +1,88 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: kernel/3.10: allow to use partition parsers for rootfs and firmware split
|
||||
|
||||
lede-commit: 3b71cd94bc9517bc25267dccb393b07d4b54564e
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/partitions.h | 2 ++
|
||||
2 files changed, 39 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||||
index f20207e32075..28f76315dfa0 100644
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -761,6 +761,36 @@ int mtd_del_partition(struct mtd_info *mtd, int partno)
|
||||
}
|
||||
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, (const struct mtd_partition **)&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->parent,
|
||||
+ parts[i].name,
|
||||
+ parts[i].offset,
|
||||
+ parts[i].size);
|
||||
+ }
|
||||
+
|
||||
+ kfree(parts);
|
||||
+
|
||||
+ return nr_parts;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||
#else
|
||||
@@ -769,6 +799,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,
|
||||
@@ -783,6 +814,12 @@ static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
|
||||
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) &&
|
||||
IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||
split_firmware(master, part);
|
||||
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
|
||||
index baafd542432e..356e29815aa2 100644
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -74,6 +74,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 {
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: [PATCH] kernel/3.10: move squashfs check from rootfs split code into a separate file
|
||||
|
||||
lede-commit: d89bea92b31b4e157a0fa438e75370f089f73427
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/mtd/Kconfig | 2 ++
|
||||
drivers/mtd/Makefile | 2 ++
|
||||
2 files changed, 4 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
|
||||
index f5ac04e288eb..4185e04760dd 100644
|
||||
--- 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
|
||||
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
|
||||
index 151d60df303a..48fd01e9f6e3 100644
|
||||
--- 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
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,103 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: kernel/3.10: add separate rootfs partition parser
|
||||
|
||||
lede-commit: daec7ad7688415156e2730e401503d09bd3acf91
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 29 +++++++++++++++++++++++++++++
|
||||
include/linux/mtd/mtd.h | 18 ++++++++++++++++++
|
||||
include/linux/mtd/partitions.h | 2 ++
|
||||
3 files changed, 49 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||||
index 28f76315dfa0..fce83882fd4e 100644
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -791,6 +791,17 @@ run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
|
||||
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
|
||||
@@ -1146,6 +1157,24 @@ int mtd_is_partition(const struct mtd_info *mtd)
|
||||
}
|
||||
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 mtd_to_part(mtd)->parent;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(mtdpart_get_master);
|
||||
+
|
||||
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (!mtd_is_partition(mtd))
|
||||
+ return 0;
|
||||
+
|
||||
+ return mtd_to_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)
|
||||
{
|
||||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
|
||||
index 5bb42c6dacdc..e7d5091bb447 100644
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -485,6 +485,24 @@ static inline uint32_t mtd_mod_by_eb(uint64_t sz, struct mtd_info *mtd)
|
||||
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)
|
||||
diff --git a/include/linux/mtd/partitions.h b/include/linux/mtd/partitions.h
|
||||
index 356e29815aa2..c0937ff4797b 100644
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -114,6 +114,8 @@ int mtd_is_partition(const struct mtd_info *mtd);
|
||||
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);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,161 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: mtd: implement write support for partitions covering only a part of an eraseblock (buffer data that would otherwise be erased)
|
||||
|
||||
lede-commit: 87a8e8ac1067f58ba831c4aae443f3655c31cd80
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 90 ++++++++++++++++++++++++++++++++++++++++++++-----
|
||||
include/linux/mtd/mtd.h | 4 +++
|
||||
2 files changed, 85 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||||
index fce83882fd4e..0238b0babe2f 100644
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -36,6 +36,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);
|
||||
@@ -241,13 +243,61 @@ static int part_erase(struct mtd_info *mtd, struct erase_info *instr)
|
||||
struct mtd_part *part = mtd_to_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->parent->erasesize, GFP_ATOMIC);
|
||||
+ if (!instr->erase_buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ mtd_ofs = part->offset + instr->addr;
|
||||
+ instr->erase_buf_ofs = do_div(mtd_ofs, part->parent->erasesize);
|
||||
+
|
||||
+ if (instr->erase_buf_ofs > 0) {
|
||||
+ instr->addr -= instr->erase_buf_ofs;
|
||||
+ ret = mtd_read(part->parent,
|
||||
+ instr->addr + part->offset,
|
||||
+ part->parent->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->parent->erasesize -
|
||||
+ do_div(mtd_ofs, part->parent->erasesize);
|
||||
+
|
||||
+ if (instr->erase_buf_ofs > 0) {
|
||||
+ instr->len += instr->erase_buf_ofs;
|
||||
+ ret = mtd_read(part->parent,
|
||||
+ part->offset + instr->addr +
|
||||
+ instr->len - part->parent->erasesize,
|
||||
+ part->parent->erasesize, &readlen,
|
||||
+ instr->erase_buf);
|
||||
+ } else {
|
||||
+ ret = 0;
|
||||
+ }
|
||||
+ }
|
||||
+ if (ret < 0) {
|
||||
+ kfree(instr->erase_buf);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ }
|
||||
+
|
||||
instr->addr += part->offset;
|
||||
ret = part->parent->_erase(part->parent, 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;
|
||||
}
|
||||
|
||||
@@ -255,6 +305,25 @@ void mtd_erase_callback(struct erase_info *instr)
|
||||
{
|
||||
if (instr->mtd->_erase == part_erase) {
|
||||
struct mtd_part *part = mtd_to_part(instr->mtd);
|
||||
+ size_t wrlen = 0;
|
||||
+
|
||||
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
|
||||
+ if (instr->partial_start) {
|
||||
+ part->parent->_write(part->parent,
|
||||
+ instr->addr, instr->erase_buf_ofs,
|
||||
+ &wrlen, instr->erase_buf);
|
||||
+ instr->addr += instr->erase_buf_ofs;
|
||||
+ } else {
|
||||
+ instr->len -= instr->erase_buf_ofs;
|
||||
+ part->parent->_write(part->parent,
|
||||
+ instr->addr + instr->len,
|
||||
+ instr->erase_buf_ofs, &wrlen,
|
||||
+ instr->erase_buf +
|
||||
+ part->parent->erasesize -
|
||||
+ instr->erase_buf_ofs);
|
||||
+ }
|
||||
+ kfree(instr->erase_buf);
|
||||
+ }
|
||||
|
||||
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||
instr->fail_addr -= part->offset;
|
||||
@@ -590,19 +659,22 @@ static struct mtd_part *allocate_partition(struct mtd_info *parent,
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
|
||||
/* 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/write block boundary -- force read-only\n",
|
||||
- part->name);
|
||||
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||
+ if (((u32)slave->mtd.size) > parent->erasesize)
|
||||
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
+ else
|
||||
+ slave->mtd.erasesize = slave->mtd.size;
|
||||
}
|
||||
|
||||
- tmp = slave->mtd.size;
|
||||
+ tmp = slave->offset + slave->mtd.size;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
|
||||
- slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase/write block -- force read-only\n",
|
||||
- part->name);
|
||||
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||
+
|
||||
+ if ((u32)slave->mtd.size > parent->erasesize)
|
||||
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
+ else
|
||||
+ slave->mtd.erasesize = slave->mtd.size;
|
||||
}
|
||||
|
||||
mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
|
||||
diff --git a/include/linux/mtd/mtd.h b/include/linux/mtd/mtd.h
|
||||
index e7d5091bb447..0db85491f085 100644
|
||||
--- 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 {
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From: Tim Harvey <tharvey@gateworks.com>
|
||||
Subject: mtd: allow partial block unlock
|
||||
|
||||
This allows sysupgrade for devices such as the Gateworks Avila/Cambria
|
||||
product families based on the ixp4xx using the redboot bootloader with
|
||||
combined FIS directory and RedBoot config partitions on larger FLASH
|
||||
devices with larger eraseblocks.
|
||||
|
||||
This second iteration of this patch addresses previous issues:
|
||||
- whitespace breakage fixed
|
||||
- unlock in all scenarios
|
||||
- simplification and fix logic bug
|
||||
|
||||
[john@phrozen.org: this should be moved to the ixp4xx folder]
|
||||
|
||||
Signed-off-by: Tim Harvey <tharvey@gateworks.com>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 11 ++++++++++-
|
||||
1 file changed, 10 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/mtd/mtdpart.c b/drivers/mtd/mtdpart.c
|
||||
index 0238b0babe2f..d41418524833 100644
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -343,7 +343,16 @@ static int part_lock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
{
|
||||
struct mtd_part *part = mtd_to_part(mtd);
|
||||
- return part->parent->_unlock(part->parent, 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->parent) + 1) * part->parent->erasesize;
|
||||
+ ofs &= ~(part->parent->erasesize - 1);
|
||||
+ }
|
||||
+
|
||||
+ return part->parent->_unlock(part->parent, ofs, len);
|
||||
}
|
||||
|
||||
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||
--
|
||||
2.11.0
|
||||
|
||||
46
target/linux/generic/pending-4.9/420-mtd-redboot_space.patch
Normal file
46
target/linux/generic/pending-4.9/420-mtd-redboot_space.patch
Normal file
@@ -0,0 +1,46 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: add patch for including unpartitioned space in the rootfs partition for redboot devices (if applicable)
|
||||
|
||||
[john@phrozen.org: used by ixp and others]
|
||||
|
||||
lede-commit: 394918851f84e4d00fa16eb900e7700e95091f00
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/redboot.c | 19 +++++++++++++------
|
||||
1 file changed, 13 insertions(+), 6 deletions(-)
|
||||
|
||||
diff --git a/drivers/mtd/redboot.c b/drivers/mtd/redboot.c
|
||||
index 7623ac5fc586..181ea0fb3c91 100644
|
||||
--- a/drivers/mtd/redboot.c
|
||||
+++ b/drivers/mtd/redboot.c
|
||||
@@ -265,14 +265,21 @@ static int parse_redboot_partitions(struct mtd_info *master,
|
||||
#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);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Subject: Add myloader partition table parser
|
||||
|
||||
[john@phozen.org: shoud be upstreamable]
|
||||
|
||||
lede-commit: d8bf22859b51faa09d22c056fe221a45d2f7a3b8
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
---
|
||||
drivers/mtd/Kconfig | 16 ++++++++++++++++
|
||||
drivers/mtd/Makefile | 1 +
|
||||
2 files changed, 17 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/Kconfig b/drivers/mtd/Kconfig
|
||||
index 4185e04760dd..cb55144d4db6 100644
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -178,6 +178,22 @@ menu "Partition parsers"
|
||||
source "drivers/mtd/parsers/Kconfig"
|
||||
endmenu
|
||||
|
||||
+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"
|
||||
|
||||
#
|
||||
diff --git a/drivers/mtd/Makefile b/drivers/mtd/Makefile
|
||||
index 48fd01e9f6e3..5bca69c63bdc 100644
|
||||
--- 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
|
||||
obj-y += parsers/
|
||||
|
||||
# 'Users' - code which presents functionality to userspace.
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Subject: [PATCH] mtd: bcm47xxpart: check for bad blocks when calculating offsets
|
||||
|
||||
Signed-off-by: Rafał Miłecki <zajec5@gmail.com>
|
||||
---
|
||||
|
||||
--- a/drivers/mtd/parsers/parser_trx.c
|
||||
+++ b/drivers/mtd/parsers/parser_trx.c
|
||||
@@ -29,6 +29,33 @@ struct trx_header {
|
||||
uint32_t offset[3];
|
||||
} __packed;
|
||||
|
||||
+/*
|
||||
+ * Calculate real end offset (address) for a given amount of data. It checks
|
||||
+ * all blocks skipping bad ones.
|
||||
+ */
|
||||
+static size_t parser_trx_real_offset(struct mtd_info *mtd, size_t bytes)
|
||||
+{
|
||||
+ size_t real_offset = 0;
|
||||
+
|
||||
+ if (mtd_block_isbad(mtd, real_offset))
|
||||
+ pr_warn("Base offset shouldn't be at bad block");
|
||||
+
|
||||
+ while (bytes >= mtd->erasesize) {
|
||||
+ bytes -= mtd->erasesize;
|
||||
+ real_offset += mtd->erasesize;
|
||||
+ while (mtd_block_isbad(mtd, real_offset)) {
|
||||
+ real_offset += mtd->erasesize;
|
||||
+
|
||||
+ if (real_offset >= mtd->size)
|
||||
+ return real_offset - mtd->erasesize;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ real_offset += bytes;
|
||||
+
|
||||
+ return real_offset;
|
||||
+}
|
||||
+
|
||||
static const char *parser_trx_data_part_name(struct mtd_info *master,
|
||||
size_t offset)
|
||||
{
|
||||
@@ -83,21 +110,21 @@ static int parser_trx_parse(struct mtd_i
|
||||
if (trx.offset[2]) {
|
||||
part = &parts[curr_part++];
|
||||
part->name = "loader";
|
||||
- part->offset = trx.offset[i];
|
||||
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (trx.offset[i]) {
|
||||
part = &parts[curr_part++];
|
||||
part->name = "linux";
|
||||
- part->offset = trx.offset[i];
|
||||
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
if (trx.offset[i]) {
|
||||
part = &parts[curr_part++];
|
||||
part->name = parser_trx_data_part_name(mtd, trx.offset[i]);
|
||||
- part->offset = trx.offset[i];
|
||||
+ part->offset = parser_trx_real_offset(mtd, trx.offset[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <zajec5@gmail.com>
|
||||
Subject: mtd: bcm47xxpart: detect T_Meter partition
|
||||
|
||||
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
|
||||
@@ -182,6 +183,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) {
|
||||
121
target/linux/generic/pending-4.9/440-block2mtd_init.patch
Normal file
121
target/linux/generic/pending-4.9/440-block2mtd_init.patch
Normal file
@@ -0,0 +1,121 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: block2mtd
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/devices/block2mtd.c | 30 ++++++++++++++++++++----------
|
||||
1 file changed, 20 insertions(+), 10 deletions(-)
|
||||
|
||||
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
|
||||
index 7c887f111a7d..22135cc48879 100644
|
||||
--- a/drivers/mtd/devices/block2mtd.c
|
||||
+++ b/drivers/mtd/devices/block2mtd.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -219,7 +220,7 @@ static void block2mtd_free_device(struct block2mtd_dev *dev)
|
||||
|
||||
|
||||
static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
- int timeout)
|
||||
+ const char *mtdname, int timeout)
|
||||
{
|
||||
#ifndef MODULE
|
||||
int i;
|
||||
@@ -227,6 +228,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
const fmode_t mode = FMODE_READ | FMODE_WRITE | FMODE_EXCL;
|
||||
struct block_device *bdev = ERR_PTR(-ENODEV);
|
||||
struct block2mtd_dev *dev;
|
||||
+ struct mtd_partition *part;
|
||||
char *name;
|
||||
|
||||
if (!devname)
|
||||
@@ -283,13 +285,16 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
|
||||
/* Setup the MTD structure */
|
||||
/* make the name contain the block device in */
|
||||
- name = kasprintf(GFP_KERNEL, "block2mtd: %s", devname);
|
||||
+ if (!mtdname)
|
||||
+ mtdname = devname;
|
||||
+ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
|
||||
if (!name)
|
||||
goto err_destroy_mutex;
|
||||
|
||||
+ strcpy(name, mtdname);
|
||||
dev->mtd.name = name;
|
||||
|
||||
- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
|
||||
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
|
||||
dev->mtd.erasesize = erase_size;
|
||||
dev->mtd.writesize = 1;
|
||||
dev->mtd.writebufsize = PAGE_SIZE;
|
||||
@@ -302,7 +307,11 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
dev->mtd.priv = dev;
|
||||
dev->mtd.owner = THIS_MODULE;
|
||||
|
||||
- if (mtd_device_register(&dev->mtd, NULL, 0)) {
|
||||
+ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
|
||||
+ part->name = name;
|
||||
+ part->offset = 0;
|
||||
+ part->size = dev->mtd.size;
|
||||
+ if (mtd_device_register(&dev->mtd, part, 1)) {
|
||||
/* Device didn't get added, so free the entry */
|
||||
goto err_destroy_mutex;
|
||||
}
|
||||
@@ -310,8 +319,7 @@ static struct block2mtd_dev *add_device(char *devname, int erase_size,
|
||||
list_add(&dev->list, &blkmtd_device_list);
|
||||
pr_info("mtd%d: [%s] erase_size = %dKiB [%d]\n",
|
||||
dev->mtd.index,
|
||||
- dev->mtd.name + strlen("block2mtd: "),
|
||||
- dev->mtd.erasesize >> 10, dev->mtd.erasesize);
|
||||
+ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
|
||||
return dev;
|
||||
|
||||
err_destroy_mutex:
|
||||
@@ -384,7 +392,7 @@ static int block2mtd_setup2(const char *val)
|
||||
/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
|
||||
char buf[80 + 12 + 80 + 8];
|
||||
char *str = buf;
|
||||
- char *token[2];
|
||||
+ char *token[3];
|
||||
char *name;
|
||||
size_t erase_size = PAGE_SIZE;
|
||||
unsigned long timeout = MTD_DEFAULT_TIMEOUT;
|
||||
@@ -398,7 +406,7 @@ static int block2mtd_setup2(const char *val)
|
||||
strcpy(str, val);
|
||||
kill_final_newline(str);
|
||||
|
||||
- for (i = 0; i < 2; i++)
|
||||
+ for (i = 0; i < 3; i++)
|
||||
token[i] = strsep(&str, ",");
|
||||
|
||||
if (str) {
|
||||
@@ -424,8 +432,10 @@ static int block2mtd_setup2(const char *val)
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
+ if (token[2] && (strlen(token[2]) + 1 > 80))
|
||||
+ pr_err("mtd device name too long\n");
|
||||
|
||||
- add_device(name, erase_size, timeout);
|
||||
+ add_device(name, erase_size, token[2], timeout);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -459,7 +469,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
|
||||
52
target/linux/generic/pending-4.9/441-block2mtd_probe.patch
Normal file
52
target/linux/generic/pending-4.9/441-block2mtd_probe.patch
Normal file
@@ -0,0 +1,52 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: block2mtd
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/devices/block2mtd.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/mtd/devices/block2mtd.c b/drivers/mtd/devices/block2mtd.c
|
||||
index 22135cc48879..9865041c347b 100644
|
||||
--- a/drivers/mtd/devices/block2mtd.c
|
||||
+++ b/drivers/mtd/devices/block2mtd.c
|
||||
@@ -392,7 +392,7 @@ static int block2mtd_setup2(const char *val)
|
||||
/* 80 for device, 12 for erase size, 80 for name, 8 for timeout */
|
||||
char buf[80 + 12 + 80 + 8];
|
||||
char *str = buf;
|
||||
- char *token[3];
|
||||
+ char *token[4];
|
||||
char *name;
|
||||
size_t erase_size = PAGE_SIZE;
|
||||
unsigned long timeout = MTD_DEFAULT_TIMEOUT;
|
||||
@@ -406,7 +406,7 @@ static int block2mtd_setup2(const char *val)
|
||||
strcpy(str, val);
|
||||
kill_final_newline(str);
|
||||
|
||||
- for (i = 0; i < 3; i++)
|
||||
+ for (i = 0; i < 4; i++)
|
||||
token[i] = strsep(&str, ",");
|
||||
|
||||
if (str) {
|
||||
@@ -435,6 +435,9 @@ static int block2mtd_setup2(const char *val)
|
||||
if (token[2] && (strlen(token[2]) + 1 > 80))
|
||||
pr_err("mtd device name too long\n");
|
||||
|
||||
+ if (token[3] && kstrtoul(token[3], 0, &timeout))
|
||||
+ pr_err("invalid timeout\n");
|
||||
+
|
||||
add_device(name, erase_size, token[2], timeout);
|
||||
|
||||
return 0;
|
||||
@@ -469,7 +472,7 @@ static int block2mtd_setup(const char *val, struct kernel_param *kp)
|
||||
|
||||
|
||||
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)
|
||||
{
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: disable cfi cmdset 0002 erase suspend
|
||||
|
||||
on some platforms, erase suspend leads to data corruption and lockups when write
|
||||
ops collide with erase ops. this has been observed on the buffalo wzr-hp-g300nh.
|
||||
rather than play whack-a-mole with a hard to reproduce issue on a variety of devices,
|
||||
simply disable erase suspend, as it will usually not produce any useful gain on
|
||||
the small filesystems used on embedded hardware.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/chips/cfi_cmdset_0002.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/drivers/mtd/chips/cfi_cmdset_0002.c b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
index 9dca881bb378..ea4db1917334 100644
|
||||
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
@@ -807,7 +807,7 @@ static int get_chip(struct map_info *map, struct flchip *chip, unsigned long adr
|
||||
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;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
From: George Kashperko <george@znau.edu.ua>
|
||||
Subject: 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
|
||||
@@ -1828,6 +1828,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;
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: Disable software protection bits for Macronix flashes.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
|
||||
index 54868b19bf32..30adbc34ccac 100644
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -1588,6 +1588,7 @@ int spi_nor_scan(struct spi_nor *nor, const char *name, enum read_mode mode)
|
||||
|
||||
if (JEDEC_MFR(info) == SNOR_MFR_ATMEL ||
|
||||
JEDEC_MFR(info) == SNOR_MFR_INTEL ||
|
||||
+ JEDEC_MFR(info) == SNOR_MFR_MACRONIX ||
|
||||
JEDEC_MFR(info) == SNOR_MFR_SST ||
|
||||
info->flags & SPI_NOR_HAS_LOCK) {
|
||||
write_enable(nor);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
From: Piotr Dymacz <pepe2k@gmail.com>
|
||||
Subject: kernel/mtd: add support for EON EN25Q128
|
||||
|
||||
Signed-off-by: Piotr Dymacz <pepe2k@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
|
||||
index 30adbc34ccac..8c0ad628ddc6 100644
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -954,6 +954,7 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "en25q32b", INFO(0x1c3016, 0, 64 * 1024, 64, 0) },
|
||||
{ "en25p64", INFO(0x1c2017, 0, 64 * 1024, 128, 0) },
|
||||
{ "en25q64", INFO(0x1c3017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
+ { "en25q128", INFO(0x1c3018, 0, 64 * 1024, 256, SECT_4K) },
|
||||
{ "en25qh128", INFO(0x1c7018, 0, 64 * 1024, 256, 0) },
|
||||
{ "en25qh256", INFO(0x1c7019, 0, 64 * 1024, 512, 0) },
|
||||
{ "en25s64", INFO(0x1c3817, 0, 64 * 1024, 128, SECT_4K) },
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
From: André Valentin <avalentin@marcant.net>
|
||||
Subject: linux/mtd: add id for mx25u3235f needed by ZyXEL NBG6817
|
||||
|
||||
Signed-off-by: André Valentin <avalentin@marcant.net>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
diff --git a/drivers/mtd/spi-nor/spi-nor.c b/drivers/mtd/spi-nor/spi-nor.c
|
||||
index 8c0ad628ddc6..5288fcfbdb3b 100644
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -1014,6 +1014,7 @@ static const struct flash_info spi_nor_ids[] = {
|
||||
{ "mx25l3205d", INFO(0xc22016, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "mx25l3255e", INFO(0xc29e16, 0, 64 * 1024, 64, SECT_4K) },
|
||||
{ "mx25l6405d", INFO(0xc22017, 0, 64 * 1024, 128, SECT_4K) },
|
||||
+ { "mx25u3235f", INFO(0xc22536, 0, 64 * 1024, 64, 0) },
|
||||
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: kernel/3.1[02]: move MTD root device setup code to mtdcore
|
||||
|
||||
The current code only allows to automatically set
|
||||
root device on MTD partitions. Move the code to MTD
|
||||
core to allow to use it with all MTD devices.
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/mtd/mtdcore.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
diff --git a/drivers/mtd/mtdcore.c b/drivers/mtd/mtdcore.c
|
||||
index d46e4adf6d2b..4d62d898dadc 100644
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -40,6 +40,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/reboot.h>
|
||||
#include <linux/leds.h>
|
||||
+#include <linux/root_dev.h>
|
||||
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
@@ -570,6 +571,15 @@ int add_mtd_device(struct mtd_info *mtd)
|
||||
of this try_ nonsense, and no bitching about it
|
||||
either. :) */
|
||||
__module_get(THIS_MODULE);
|
||||
+
|
||||
+ if (!strcmp(mtd->name, "rootfs") &&
|
||||
+ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
|
||||
+ ROOT_DEV == 0) {
|
||||
+ pr_notice("mtd: device %d (%s) set to be root filesystem\n",
|
||||
+ mtd->index, mtd->name);
|
||||
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, mtd->index);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
fail_added:
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Subject: ubi: auto-attach mtd device named "ubi" or "data" on boot
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/build.c | 36 ++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/ubi/build.c
|
||||
+++ b/drivers/mtd/ubi/build.c
|
||||
@@ -1212,6 +1212,49 @@ static struct mtd_info * __init open_mtd
|
||||
return mtd;
|
||||
}
|
||||
|
||||
+/*
|
||||
+ * This function tries attaching mtd partitions named either "ubi" or "data"
|
||||
+ * during boot.
|
||||
+ */
|
||||
+static void __init ubi_auto_attach(void)
|
||||
+{
|
||||
+ int err;
|
||||
+ struct mtd_info *mtd;
|
||||
+
|
||||
+ /* try attaching mtd device named "ubi" or "data" */
|
||||
+ mtd = open_mtd_device("ubi");
|
||||
+ if (IS_ERR(mtd))
|
||||
+ mtd = open_mtd_device("data");
|
||||
+
|
||||
+ if (!IS_ERR(mtd)) {
|
||||
+ size_t len;
|
||||
+ char magic[4];
|
||||
+
|
||||
+ /* check for a valid ubi magic */
|
||||
+ err = mtd_read(mtd, 0, 4, &len, (void *) magic);
|
||||
+ if (!err && len == 4 && strncmp(magic, "UBI#", 4)) {
|
||||
+ pr_err("UBI error: no valid UBI magic found inside mtd%d", mtd->index);
|
||||
+ put_mtd_device(mtd);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* auto-add only media types where UBI makes sense */
|
||||
+ if (mtd->type == MTD_NANDFLASH ||
|
||||
+ mtd->type == MTD_NORFLASH ||
|
||||
+ mtd->type == MTD_DATAFLASH ||
|
||||
+ mtd->type == MTD_MLCNANDFLASH) {
|
||||
+ mutex_lock(&ubi_devices_mutex);
|
||||
+ pr_notice("UBI: auto-attach mtd%d\n", mtd->index);
|
||||
+ err = ubi_attach_mtd_dev(mtd, UBI_DEV_NUM_AUTO, 0, 0);
|
||||
+ mutex_unlock(&ubi_devices_mutex);
|
||||
+ if (err < 0) {
|
||||
+ pr_err("UBI error: cannot attach mtd%d", mtd->index);
|
||||
+ put_mtd_device(mtd);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static int __init ubi_init(void)
|
||||
{
|
||||
int err, i, k;
|
||||
@@ -1295,6 +1338,12 @@ static int __init ubi_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
+ /* auto-attach mtd devices only if built-in to the kernel and no ubi.mtd
|
||||
+ * parameter was given */
|
||||
+ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
|
||||
+ !ubi_is_module() && !mtd_devs)
|
||||
+ ubi_auto_attach();
|
||||
+
|
||||
err = ubiblock_init();
|
||||
if (err) {
|
||||
pr_err("UBI error: block: cannot initialize, error %d", err);
|
||||
@@ -0,0 +1,66 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Subject: ubi: auto-create ubiblock device for rootfs
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/block.c | 42 ++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 42 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -627,6 +627,44 @@ static void __init ubiblock_create_from_
|
||||
}
|
||||
}
|
||||
|
||||
+#define UBIFS_NODE_MAGIC 0x06101831
|
||||
+static inline int ubi_vol_is_ubifs(struct ubi_volume_desc *desc)
|
||||
+{
|
||||
+ int ret;
|
||||
+ uint32_t magic_of, magic;
|
||||
+ ret = ubi_read(desc, 0, (char *)&magic_of, 0, 4);
|
||||
+ if (ret)
|
||||
+ return 0;
|
||||
+ magic = le32_to_cpu(magic_of);
|
||||
+ return magic == UBIFS_NODE_MAGIC;
|
||||
+}
|
||||
+
|
||||
+static void __init ubiblock_create_auto_rootfs(void)
|
||||
+{
|
||||
+ int ubi_num, ret, is_ubifs;
|
||||
+ struct ubi_volume_desc *desc;
|
||||
+ struct ubi_volume_info vi;
|
||||
+
|
||||
+ for (ubi_num = 0; ubi_num < UBI_MAX_DEVICES; ubi_num++) {
|
||||
+ desc = ubi_open_volume_nm(ubi_num, "rootfs", UBI_READONLY);
|
||||
+ if (IS_ERR(desc))
|
||||
+ continue;
|
||||
+
|
||||
+ ubi_get_volume_info(desc, &vi);
|
||||
+ is_ubifs = ubi_vol_is_ubifs(desc);
|
||||
+ ubi_close_volume(desc);
|
||||
+ if (is_ubifs)
|
||||
+ break;
|
||||
+
|
||||
+ ret = ubiblock_create(&vi);
|
||||
+ if (ret)
|
||||
+ pr_err("UBI error: block: can't add '%s' volume, err=%d\n",
|
||||
+ vi.name, ret);
|
||||
+ /* always break if we get here */
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static void ubiblock_remove_all(void)
|
||||
{
|
||||
struct ubiblock *next;
|
||||
@@ -657,6 +695,10 @@ int __init ubiblock_init(void)
|
||||
*/
|
||||
ubiblock_create_from_param();
|
||||
|
||||
+ /* auto-attach "rootfs" volume if existing and non-ubifs */
|
||||
+ if (IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV))
|
||||
+ ubiblock_create_auto_rootfs();
|
||||
+
|
||||
/*
|
||||
* Block devices are only created upon user requests, so we ignore
|
||||
* existing volumes.
|
||||
@@ -0,0 +1,51 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Subject: try auto-mounting ubi0:rootfs in init/do_mounts.c
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
init/do_mounts.c | 26 +++++++++++++++++++++++++-
|
||||
1 file changed, 25 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/init/do_mounts.c
|
||||
+++ b/init/do_mounts.c
|
||||
@@ -438,7 +438,28 @@ retry:
|
||||
out:
|
||||
put_page(page);
|
||||
}
|
||||
-
|
||||
+
|
||||
+static int __init mount_ubi_rootfs(void)
|
||||
+{
|
||||
+ int flags = MS_SILENT;
|
||||
+ int err, tried = 0;
|
||||
+
|
||||
+ while (tried < 2) {
|
||||
+ err = do_mount_root("ubi0:rootfs", "ubifs", flags, \
|
||||
+ root_mount_data);
|
||||
+ switch (err) {
|
||||
+ case -EACCES:
|
||||
+ flags |= MS_RDONLY;
|
||||
+ tried++;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return err;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
#ifdef CONFIG_ROOT_NFS
|
||||
|
||||
#define NFSROOT_TIMEOUT_MIN 5
|
||||
@@ -532,6 +553,10 @@ void __init mount_root(void)
|
||||
change_floppy("root floppy");
|
||||
}
|
||||
#endif
|
||||
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
|
||||
+ if (!mount_ubi_rootfs())
|
||||
+ return;
|
||||
+#endif
|
||||
#ifdef CONFIG_BLOCK
|
||||
{
|
||||
int err = create_dev("/dev/root", ROOT_DEV);
|
||||
@@ -0,0 +1,34 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Subject: ubi: set ROOT_DEV to ubiblock "rootfs" if unset
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/mtd/ubi/block.c | 10 ++++++++++
|
||||
1 file changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/ubi/block.c
|
||||
+++ b/drivers/mtd/ubi/block.c
|
||||
@@ -50,6 +50,7 @@
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/idr.h>
|
||||
#include <asm/div64.h>
|
||||
+#include <linux/root_dev.h>
|
||||
|
||||
#include "ubi-media.h"
|
||||
#include "ubi.h"
|
||||
@@ -447,6 +448,15 @@ int ubiblock_create(struct ubi_volume_in
|
||||
add_disk(dev->gd);
|
||||
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
|
||||
dev->ubi_num, dev->vol_id, vi->name);
|
||||
+
|
||||
+ if (!strcmp(vi->name, "rootfs") &&
|
||||
+ IS_ENABLED(CONFIG_MTD_ROOTFS_ROOT_DEV) &&
|
||||
+ ROOT_DEV == 0) {
|
||||
+ pr_notice("ubiblock: device ubiblock%d_%d (%s) set to be root filesystem\n",
|
||||
+ dev->ubi_num, dev->vol_id, vi->name);
|
||||
+ ROOT_DEV = MKDEV(gd->major, gd->first_minor);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
|
||||
out_free_queue:
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: mtd: add EOF marker support to the UBI layer
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/mtd/ubi/attach.c | 25 ++++++++++++++++++++++---
|
||||
drivers/mtd/ubi/ubi.h | 1 +
|
||||
2 files changed, 23 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/mtd/ubi/attach.c b/drivers/mtd/ubi/attach.c
|
||||
index 93ceea4f27d5..a4f849d69104 100644
|
||||
--- a/drivers/mtd/ubi/attach.c
|
||||
+++ b/drivers/mtd/ubi/attach.c
|
||||
@@ -939,6 +939,13 @@ static bool vol_ignored(int vol_id)
|
||||
#endif
|
||||
}
|
||||
|
||||
+static bool ec_hdr_has_eof(struct ubi_ec_hdr *ech)
|
||||
+{
|
||||
+ return ech->padding1[0] == 'E' &&
|
||||
+ ech->padding1[1] == 'O' &&
|
||||
+ ech->padding1[2] == 'F';
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* scan_peb - scan and process UBI headers of a PEB.
|
||||
* @ubi: UBI device description object
|
||||
@@ -971,9 +978,21 @@ static int scan_peb(struct ubi_device *ubi, struct ubi_attach_info *ai,
|
||||
return 0;
|
||||
}
|
||||
|
||||
- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
|
||||
- if (err < 0)
|
||||
- return err;
|
||||
+ if (!ai->eof_found) {
|
||||
+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ if (ec_hdr_has_eof(ech)) {
|
||||
+ pr_notice("UBI: EOF marker found, PEBs from %d will be erased",
|
||||
+ pnum);
|
||||
+ ai->eof_found = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (ai->eof_found)
|
||||
+ err = UBI_IO_FF_BITFLIPS;
|
||||
+
|
||||
switch (err) {
|
||||
case 0:
|
||||
break;
|
||||
diff --git a/drivers/mtd/ubi/ubi.h b/drivers/mtd/ubi/ubi.h
|
||||
index 697dbcba7371..92d207ff2458 100644
|
||||
--- a/drivers/mtd/ubi/ubi.h
|
||||
+++ b/drivers/mtd/ubi/ubi.h
|
||||
@@ -779,6 +779,7 @@ struct ubi_attach_info {
|
||||
int mean_ec;
|
||||
uint64_t ec_sum;
|
||||
int ec_count;
|
||||
+ bool eof_found;
|
||||
struct kmem_cache *aeb_slab_cache;
|
||||
struct ubi_ec_hdr *ech;
|
||||
struct ubi_vid_io_buf *vidb;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
5232
target/linux/generic/pending-4.9/530-jffs2_make_lzma_available.patch
Normal file
5232
target/linux/generic/pending-4.9/530-jffs2_make_lzma_available.patch
Normal file
File diff suppressed because it is too large
Load Diff
72
target/linux/generic/pending-4.9/532-jffs2_eofdetect.patch
Normal file
72
target/linux/generic/pending-4.9/532-jffs2_eofdetect.patch
Normal file
@@ -0,0 +1,72 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: fs: jffs2: EOF marker
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
fs/jffs2/build.c | 10 ++++++++++
|
||||
fs/jffs2/scan.c | 21 +++++++++++++++++++--
|
||||
2 files changed, 29 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/fs/jffs2/build.c b/fs/jffs2/build.c
|
||||
index b288c8ae1236..e768f9d41661 100644
|
||||
--- a/fs/jffs2/build.c
|
||||
+++ b/fs/jffs2/build.c
|
||||
@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct jffs2_sb_info *c)
|
||||
dbg_fsbuild("scanned flash completely\n");
|
||||
jffs2_dbg_dump_block_lists_nolock(c);
|
||||
|
||||
+ if (c->flags & (1 << 7)) {
|
||||
+ printk("%s(): unlocking the mtd device... ", __func__);
|
||||
+ mtd_unlock(c->mtd, 0, c->mtd->size);
|
||||
+ printk("done.\n");
|
||||
+
|
||||
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
|
||||
+ jffs2_erase_pending_blocks(c, -1);
|
||||
+ printk("done.\n");
|
||||
+ }
|
||||
+
|
||||
dbg_fsbuild("pass 1 starting\n");
|
||||
c->flags |= JFFS2_SB_FLAG_BUILDING;
|
||||
/* Now scan the directory tree, increasing nlink according to every dirent found. */
|
||||
diff --git a/fs/jffs2/scan.c b/fs/jffs2/scan.c
|
||||
index 90431dd613b8..8c78ab19cdab 100644
|
||||
--- a/fs/jffs2/scan.c
|
||||
+++ b/fs/jffs2/scan.c
|
||||
@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_info *c)
|
||||
/* reset summary info for next eraseblock scan */
|
||||
jffs2_sum_reset_collected(s);
|
||||
|
||||
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
|
||||
- buf_size, s);
|
||||
+ if (c->flags & (1 << 7)) {
|
||||
+ if (mtd_block_isbad(c->mtd, jeb->offset))
|
||||
+ ret = BLK_STATE_BADBLOCK;
|
||||
+ else
|
||||
+ ret = BLK_STATE_ALLFF;
|
||||
+ } else
|
||||
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
|
||||
+ buf_size, s);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@@ -561,6 +567,17 @@ static int jffs2_scan_eraseblock (struct jffs2_sb_info *c, struct jffs2_eraseblo
|
||||
return err;
|
||||
}
|
||||
|
||||
+ if ((buf[0] == 0xde) &&
|
||||
+ (buf[1] == 0xad) &&
|
||||
+ (buf[2] == 0xc0) &&
|
||||
+ (buf[3] == 0xde)) {
|
||||
+ /* end of filesystem. erase everything after this point */
|
||||
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
|
||||
+ c->flags |= (1 << 7);
|
||||
+
|
||||
+ return BLK_STATE_ALLFF;
|
||||
+ }
|
||||
+
|
||||
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
|
||||
ofs = 0;
|
||||
max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: fs: ubifs: fix default compression selection in ubifs
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
fs/ubifs/sb.c | 13 ++++++++++++-
|
||||
1 file changed, 12 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/fs/ubifs/sb.c b/fs/ubifs/sb.c
|
||||
index 3cbb904a6d7d..460cb9e3b4ea 100644
|
||||
--- a/fs/ubifs/sb.c
|
||||
+++ b/fs/ubifs/sb.c
|
||||
@@ -63,6 +63,17 @@
|
||||
/* Default time granularity in nanoseconds */
|
||||
#define DEFAULT_TIME_GRAN 1000000000
|
||||
|
||||
+static int get_default_compressor(void)
|
||||
+{
|
||||
+ if (ubifs_compr_present(UBIFS_COMPR_LZO))
|
||||
+ return UBIFS_COMPR_LZO;
|
||||
+
|
||||
+ if (ubifs_compr_present(UBIFS_COMPR_ZLIB))
|
||||
+ return UBIFS_COMPR_ZLIB;
|
||||
+
|
||||
+ return UBIFS_COMPR_NONE;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* create_default_filesystem - format empty UBI volume.
|
||||
* @c: UBIFS file-system description object
|
||||
@@ -183,7 +194,7 @@ static int create_default_filesystem(struct ubifs_info *c)
|
||||
if (c->mount_opts.override_compr)
|
||||
sup->default_compr = cpu_to_le16(c->mount_opts.compr_type);
|
||||
else
|
||||
- sup->default_compr = cpu_to_le16(UBIFS_COMPR_LZO);
|
||||
+ sup->default_compr = cpu_to_le16(get_default_compressor());
|
||||
|
||||
generate_random_uuid(sup->uuid);
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: netfilter: add support for flushing conntrack via /proc
|
||||
|
||||
lede-commit 8193bbe59a74d34d6a26d4a8cb857b1952905314
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/netfilter/nf_conntrack_standalone.c | 59 ++++++++++++++++++++++++++++++++-
|
||||
1 file changed, 58 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
|
||||
index 5f446cd9f3fd..4c1856b5151f 100644
|
||||
--- a/net/netfilter/nf_conntrack_standalone.c
|
||||
+++ b/net/netfilter/nf_conntrack_standalone.c
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/security.h>
|
||||
+#include <linux/inet.h>
|
||||
#include <net/net_namespace.h>
|
||||
#ifdef CONFIG_SYSCTL
|
||||
#include <linux/sysctl.h>
|
||||
@@ -298,10 +299,66 @@ static int ct_open(struct inode *inode, struct file *file)
|
||||
sizeof(struct ct_iter_state));
|
||||
}
|
||||
|
||||
+struct kill_request {
|
||||
+ u16 family;
|
||||
+ union nf_inet_addr addr;
|
||||
+};
|
||||
+
|
||||
+static int kill_matching(struct nf_conn *i, void *data)
|
||||
+{
|
||||
+ struct kill_request *kr = data;
|
||||
+ struct nf_conntrack_tuple *t1 = &i->tuplehash[IP_CT_DIR_ORIGINAL].tuple;
|
||||
+ struct nf_conntrack_tuple *t2 = &i->tuplehash[IP_CT_DIR_REPLY].tuple;
|
||||
+
|
||||
+ if (!kr->family)
|
||||
+ return 1;
|
||||
+
|
||||
+ if (t1->src.l3num != kr->family)
|
||||
+ return 0;
|
||||
+
|
||||
+ return (nf_inet_addr_cmp(&kr->addr, &t1->src.u3) ||
|
||||
+ nf_inet_addr_cmp(&kr->addr, &t1->dst.u3) ||
|
||||
+ nf_inet_addr_cmp(&kr->addr, &t2->src.u3) ||
|
||||
+ nf_inet_addr_cmp(&kr->addr, &t2->dst.u3));
|
||||
+}
|
||||
+
|
||||
+static ssize_t ct_file_write(struct file *file, const char __user *buf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct seq_file *seq = file->private_data;
|
||||
+ struct net *net = seq_file_net(seq);
|
||||
+ struct kill_request kr = { };
|
||||
+ char req[INET6_ADDRSTRLEN] = { };
|
||||
+
|
||||
+ if (count == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (count >= INET6_ADDRSTRLEN)
|
||||
+ count = INET6_ADDRSTRLEN - 1;
|
||||
+
|
||||
+ if (copy_from_user(req, buf, count))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ if (strnchr(req, count, ':')) {
|
||||
+ kr.family = AF_INET6;
|
||||
+ if (!in6_pton(req, count, (void *)&kr.addr, '\n', NULL))
|
||||
+ return -EINVAL;
|
||||
+ } else if (strnchr(req, count, '.')) {
|
||||
+ kr.family = AF_INET;
|
||||
+ if (!in4_pton(req, count, (void *)&kr.addr, '\n', NULL))
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ nf_ct_iterate_cleanup(net, kill_matching, &kr, 0, 0);
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+
|
||||
static const struct file_operations ct_file_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = ct_open,
|
||||
.read = seq_read,
|
||||
+ .write = ct_file_write,
|
||||
.llseek = seq_lseek,
|
||||
.release = seq_release_net,
|
||||
};
|
||||
@@ -405,7 +462,7 @@ static int nf_conntrack_standalone_init_proc(struct net *net)
|
||||
kuid_t root_uid;
|
||||
kgid_t root_gid;
|
||||
|
||||
- pde = proc_create("nf_conntrack", 0440, net->proc_net, &ct_file_ops);
|
||||
+ pde = proc_create("nf_conntrack", 0660, net->proc_net, &ct_file_ops);
|
||||
if (!pde)
|
||||
goto out_nf_conntrack;
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add a new version of my netfilter speedup patches for linux 2.6.39 and 3.0
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/uapi/linux/netfilter_ipv4/ip_tables.h | 1 +
|
||||
net/ipv4/netfilter/ip_tables.c | 37 +++++++++++++++++++++++++++
|
||||
2 files changed, 38 insertions(+)
|
||||
|
||||
diff --git a/include/uapi/linux/netfilter_ipv4/ip_tables.h b/include/uapi/linux/netfilter_ipv4/ip_tables.h
|
||||
index d0da53d96d93..f279daa13c0f 100644
|
||||
--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
|
||||
+++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
|
||||
@@ -88,6 +88,7 @@ struct ipt_ip {
|
||||
#define IPT_F_FRAG 0x01 /* Set if rule is a fragment rule */
|
||||
#define IPT_F_GOTO 0x02 /* Set if jump is a goto */
|
||||
#define IPT_F_MASK 0x03 /* All possible flag bits mask. */
|
||||
+#define IPT_F_NO_DEF_MATCH 0x80 /* Internal: no default match rules present */
|
||||
|
||||
/* Values for "inv" field in struct ipt_ip. */
|
||||
#define IPT_INV_VIA_IN 0x01 /* Invert the sense of IN IFACE. */
|
||||
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
|
||||
index 7c00ce90adb8..d919350a0e8b 100644
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -58,6 +58,9 @@ ip_packet_match(const struct iphdr *ip,
|
||||
{
|
||||
unsigned long ret;
|
||||
|
||||
+ if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
|
||||
+ return true;
|
||||
+
|
||||
if (NF_INVF(ipinfo, IPT_INV_SRCIP,
|
||||
(ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
|
||||
NF_INVF(ipinfo, IPT_INV_DSTIP,
|
||||
@@ -88,6 +91,29 @@ ip_packet_match(const struct iphdr *ip,
|
||||
return true;
|
||||
}
|
||||
|
||||
+static void
|
||||
+ip_checkdefault(struct ipt_ip *ip)
|
||||
+{
|
||||
+ static const char iface_mask[IFNAMSIZ] = {};
|
||||
+
|
||||
+ if (ip->invflags || ip->flags & IPT_F_FRAG)
|
||||
+ return;
|
||||
+
|
||||
+ if (memcmp(ip->iniface_mask, iface_mask, IFNAMSIZ) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (memcmp(ip->outiface_mask, iface_mask, IFNAMSIZ) != 0)
|
||||
+ return;
|
||||
+
|
||||
+ if (ip->smsk.s_addr || ip->dmsk.s_addr)
|
||||
+ return;
|
||||
+
|
||||
+ if (ip->proto)
|
||||
+ return;
|
||||
+
|
||||
+ ip->flags |= IPT_F_NO_DEF_MATCH;
|
||||
+}
|
||||
+
|
||||
static bool
|
||||
ip_checkentry(const struct ipt_ip *ip)
|
||||
{
|
||||
@@ -545,6 +571,8 @@ find_check_entry(struct ipt_entry *e, struct net *net, const char *name,
|
||||
struct xt_entry_match *ematch;
|
||||
unsigned long pcnt;
|
||||
|
||||
+ ip_checkdefault(&e->ip);
|
||||
+
|
||||
pcnt = xt_percpu_counter_alloc();
|
||||
if (IS_ERR_VALUE(pcnt))
|
||||
return -ENOMEM;
|
||||
@@ -824,6 +852,7 @@ copy_entries_to_user(unsigned int total_size,
|
||||
const struct xt_table_info *private = table->private;
|
||||
int ret = 0;
|
||||
const void *loc_cpu_entry;
|
||||
+ u8 flags;
|
||||
|
||||
counters = alloc_counters(table);
|
||||
if (IS_ERR(counters))
|
||||
@@ -851,6 +880,14 @@ copy_entries_to_user(unsigned int total_size,
|
||||
goto free_counters;
|
||||
}
|
||||
|
||||
+ flags = e->ip.flags & IPT_F_MASK;
|
||||
+ if (copy_to_user(userptr + off
|
||||
+ + offsetof(struct ipt_entry, ip.flags),
|
||||
+ &flags, sizeof(flags)) != 0) {
|
||||
+ ret = -EFAULT;
|
||||
+ goto free_counters;
|
||||
+ }
|
||||
+
|
||||
for (i = sizeof(struct ipt_entry);
|
||||
i < e->target_offset;
|
||||
i += m->u.match_size) {
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,124 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: netfilter: match bypass default table
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/ipv4/netfilter/ip_tables.c | 79 +++++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 58 insertions(+), 21 deletions(-)
|
||||
|
||||
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
|
||||
index d919350a0e8b..9178930fca17 100644
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -254,6 +254,33 @@ struct ipt_entry *ipt_next_entry(const struct ipt_entry *entry)
|
||||
return (void *)entry + entry->next_offset;
|
||||
}
|
||||
|
||||
+static bool
|
||||
+ipt_handle_default_rule(struct ipt_entry *e, unsigned int *verdict)
|
||||
+{
|
||||
+ struct xt_entry_target *t;
|
||||
+ struct xt_standard_target *st;
|
||||
+
|
||||
+ if (e->target_offset != sizeof(struct ipt_entry))
|
||||
+ return false;
|
||||
+
|
||||
+ if (!(e->ip.flags & IPT_F_NO_DEF_MATCH))
|
||||
+ return false;
|
||||
+
|
||||
+ t = ipt_get_target(e);
|
||||
+ if (t->u.kernel.target->target)
|
||||
+ return false;
|
||||
+
|
||||
+ st = (struct xt_standard_target *) t;
|
||||
+ if (st->verdict == XT_RETURN)
|
||||
+ return false;
|
||||
+
|
||||
+ if (st->verdict >= 0)
|
||||
+ return false;
|
||||
+
|
||||
+ *verdict = (unsigned)(-st->verdict) - 1;
|
||||
+ return true;
|
||||
+}
|
||||
+
|
||||
/* Returns one of the generic firewall policies, like NF_ACCEPT. */
|
||||
unsigned int
|
||||
ipt_do_table(struct sk_buff *skb,
|
||||
@@ -274,28 +301,8 @@ ipt_do_table(struct sk_buff *skb,
|
||||
unsigned int addend;
|
||||
|
||||
/* Initialization */
|
||||
- stackidx = 0;
|
||||
- ip = ip_hdr(skb);
|
||||
- indev = state->in ? state->in->name : nulldevname;
|
||||
- outdev = state->out ? state->out->name : nulldevname;
|
||||
- /* We handle fragments by dealing with the first fragment as
|
||||
- * if it was a normal packet. All other fragments are treated
|
||||
- * normally, except that they will NEVER match rules that ask
|
||||
- * things we don't know, ie. tcp syn flag or ports). If the
|
||||
- * rule is also a fragment-specific rule, non-fragments won't
|
||||
- * match it. */
|
||||
- acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
- acpar.thoff = ip_hdrlen(skb);
|
||||
- acpar.hotdrop = false;
|
||||
- acpar.net = state->net;
|
||||
- acpar.in = state->in;
|
||||
- acpar.out = state->out;
|
||||
- acpar.family = NFPROTO_IPV4;
|
||||
- acpar.hooknum = hook;
|
||||
-
|
||||
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
||||
local_bh_disable();
|
||||
- addend = xt_write_recseq_begin();
|
||||
private = table->private;
|
||||
cpu = smp_processor_id();
|
||||
/*
|
||||
@@ -304,6 +311,23 @@ ipt_do_table(struct sk_buff *skb,
|
||||
*/
|
||||
smp_read_barrier_depends();
|
||||
table_base = private->entries;
|
||||
+
|
||||
+ e = get_entry(table_base, private->hook_entry[hook]);
|
||||
+ if (ipt_handle_default_rule(e, &verdict)) {
|
||||
+ struct xt_counters *counter;
|
||||
+
|
||||
+ counter = xt_get_this_cpu_counter(&e->counters);
|
||||
+ ADD_COUNTER(*counter, skb->len, 1);
|
||||
+ local_bh_enable();
|
||||
+ return verdict;
|
||||
+ }
|
||||
+
|
||||
+ stackidx = 0;
|
||||
+ ip = ip_hdr(skb);
|
||||
+ indev = state->in ? state->in->name : nulldevname;
|
||||
+ outdev = state->out ? state->out->name : nulldevname;
|
||||
+
|
||||
+ addend = xt_write_recseq_begin();
|
||||
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
|
||||
|
||||
/* Switch to alternate jumpstack if we're being invoked via TEE.
|
||||
@@ -316,7 +340,20 @@ ipt_do_table(struct sk_buff *skb,
|
||||
if (static_key_false(&xt_tee_enabled))
|
||||
jumpstack += private->stacksize * __this_cpu_read(nf_skb_duplicated);
|
||||
|
||||
- e = get_entry(table_base, private->hook_entry[hook]);
|
||||
+ /* We handle fragments by dealing with the first fragment as
|
||||
+ * if it was a normal packet. All other fragments are treated
|
||||
+ * normally, except that they will NEVER match rules that ask
|
||||
+ * things we don't know, ie. tcp syn flag or ports). If the
|
||||
+ * rule is also a fragment-specific rule, non-fragments won't
|
||||
+ * match it. */
|
||||
+ acpar.fragoff = ntohs(ip->frag_off) & IP_OFFSET;
|
||||
+ acpar.thoff = ip_hdrlen(skb);
|
||||
+ acpar.hotdrop = false;
|
||||
+ acpar.net = state->net;
|
||||
+ acpar.in = state->in;
|
||||
+ acpar.out = state->out;
|
||||
+ acpar.family = NFPROTO_IPV4;
|
||||
+ acpar.hooknum = hook;
|
||||
|
||||
do {
|
||||
const struct xt_entry_target *t;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: netfilter: reduce match memory access
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/ipv4/netfilter/ip_tables.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/net/ipv4/netfilter/ip_tables.c b/net/ipv4/netfilter/ip_tables.c
|
||||
index 9178930fca17..35d1db7b78f1 100644
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -61,9 +61,9 @@ ip_packet_match(const struct iphdr *ip,
|
||||
if (ipinfo->flags & IPT_F_NO_DEF_MATCH)
|
||||
return true;
|
||||
|
||||
- if (NF_INVF(ipinfo, IPT_INV_SRCIP,
|
||||
+ if (NF_INVF(ipinfo, IPT_INV_SRCIP, ipinfo->smsk.s_addr &&
|
||||
(ip->saddr & ipinfo->smsk.s_addr) != ipinfo->src.s_addr) ||
|
||||
- NF_INVF(ipinfo, IPT_INV_DSTIP,
|
||||
+ NF_INVF(ipinfo, IPT_INV_DSTIP, ipinfo->dmsk.s_addr &&
|
||||
(ip->daddr & ipinfo->dmsk.s_addr) != ipinfo->dst.s_addr))
|
||||
return false;
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: netfilter: optional tcp window check
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/netfilter/nf_conntrack_proto_tcp.c | 13 +++++++++++++
|
||||
1 file changed, 13 insertions(+)
|
||||
|
||||
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
|
||||
index 69f687740c76..f24b62668dc8 100644
|
||||
--- a/net/netfilter/nf_conntrack_proto_tcp.c
|
||||
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
|
||||
@@ -33,6 +33,9 @@
|
||||
#include <net/netfilter/ipv4/nf_conntrack_ipv4.h>
|
||||
#include <net/netfilter/ipv6/nf_conntrack_ipv6.h>
|
||||
|
||||
+/* Do not check the TCP window for incoming packets */
|
||||
+static int nf_ct_tcp_no_window_check __read_mostly = 1;
|
||||
+
|
||||
/* "Be conservative in what you do,
|
||||
be liberal in what you accept from others."
|
||||
If it's non-zero, we mark only out of window RST segments as INVALID. */
|
||||
@@ -513,6 +516,9 @@ static bool tcp_in_window(const struct nf_conn *ct,
|
||||
s32 receiver_offset;
|
||||
bool res, in_recv_win;
|
||||
|
||||
+ if (nf_ct_tcp_no_window_check)
|
||||
+ return true;
|
||||
+
|
||||
/*
|
||||
* Get the required data from the packet.
|
||||
*/
|
||||
@@ -1479,6 +1485,13 @@ static struct ctl_table tcp_sysctl_table[] = {
|
||||
.mode = 0644,
|
||||
.proc_handler = proc_dointvec,
|
||||
},
|
||||
+ {
|
||||
+ .procname = "nf_conntrack_tcp_no_window_check",
|
||||
+ .data = &nf_ct_tcp_no_window_check,
|
||||
+ .maxlen = sizeof(unsigned int),
|
||||
+ .mode = 0644,
|
||||
+ .proc_handler = proc_dointvec,
|
||||
+ },
|
||||
{ }
|
||||
};
|
||||
#endif /* CONFIG_SYSCTL */
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add a small xfrm related performance optimization
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/netfilter/nf_nat_core.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c
|
||||
index 5b9c884a452e..4ea363755085 100644
|
||||
--- a/net/netfilter/nf_nat_core.c
|
||||
+++ b/net/netfilter/nf_nat_core.c
|
||||
@@ -95,6 +95,9 @@ int nf_xfrm_me_harder(struct net *net, struct sk_buff *skb, unsigned int family)
|
||||
struct dst_entry *dst;
|
||||
int err;
|
||||
|
||||
+ if (skb->dev && !dev_net(skb->dev)->xfrm.policy_count[XFRM_POLICY_OUT])
|
||||
+ return 0;
|
||||
+
|
||||
err = xfrm_decode_session(skb, &fl, family);
|
||||
if (err < 0)
|
||||
return err;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
147
target/linux/generic/pending-4.9/630-packet_socket_type.patch
Normal file
147
target/linux/generic/pending-4.9/630-packet_socket_type.patch
Normal file
@@ -0,0 +1,147 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: net: add an optimization for dealing with raw sockets
|
||||
|
||||
lede-commit: 4898039703d7315f0f3431c860123338ec3be0f6
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/uapi/linux/if_packet.h | 3 +++
|
||||
net/packet/af_packet.c | 34 +++++++++++++++++++++++++++-------
|
||||
net/packet/internal.h | 1 +
|
||||
3 files changed, 31 insertions(+), 7 deletions(-)
|
||||
|
||||
diff --git a/include/uapi/linux/if_packet.h b/include/uapi/linux/if_packet.h
|
||||
index 9e7edfd8141e..40fdf8907900 100644
|
||||
--- a/include/uapi/linux/if_packet.h
|
||||
+++ b/include/uapi/linux/if_packet.h
|
||||
@@ -31,6 +31,8 @@ struct sockaddr_ll {
|
||||
#define PACKET_KERNEL 7 /* To kernel space */
|
||||
/* Unused, PACKET_FASTROUTE and PACKET_LOOPBACK are invisible to user space */
|
||||
#define PACKET_FASTROUTE 6 /* Fastrouted frame */
|
||||
+#define PACKET_MASK_ANY 0xffffffff /* mask for packet type bits */
|
||||
+
|
||||
|
||||
/* Packet socket options */
|
||||
|
||||
@@ -56,6 +58,7 @@ struct sockaddr_ll {
|
||||
#define PACKET_QDISC_BYPASS 20
|
||||
#define PACKET_ROLLOVER_STATS 21
|
||||
#define PACKET_FANOUT_DATA 22
|
||||
+#define PACKET_RECV_TYPE 23
|
||||
|
||||
#define PACKET_FANOUT_HASH 0
|
||||
#define PACKET_FANOUT_LB 1
|
||||
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
|
||||
index 6a563e6e24de..e412c5a4f6d4 100644
|
||||
--- a/net/packet/af_packet.c
|
||||
+++ b/net/packet/af_packet.c
|
||||
@@ -1772,6 +1772,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
|
||||
{
|
||||
struct sock *sk;
|
||||
struct sockaddr_pkt *spkt;
|
||||
+ struct packet_sock *po;
|
||||
|
||||
/*
|
||||
* When we registered the protocol we saved the socket in the data
|
||||
@@ -1779,6 +1780,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
|
||||
*/
|
||||
|
||||
sk = pt->af_packet_priv;
|
||||
+ po = pkt_sk(sk);
|
||||
|
||||
/*
|
||||
* Yank back the headers [hope the device set this
|
||||
@@ -1791,7 +1793,7 @@ static int packet_rcv_spkt(struct sk_buff *skb, struct net_device *dev,
|
||||
* so that this procedure is noop.
|
||||
*/
|
||||
|
||||
- if (skb->pkt_type == PACKET_LOOPBACK)
|
||||
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
|
||||
goto out;
|
||||
|
||||
if (!net_eq(dev_net(dev), sock_net(sk)))
|
||||
@@ -2029,12 +2031,12 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned int snaplen, res;
|
||||
bool is_drop_n_account = false;
|
||||
|
||||
- if (skb->pkt_type == PACKET_LOOPBACK)
|
||||
- goto drop;
|
||||
-
|
||||
sk = pt->af_packet_priv;
|
||||
po = pkt_sk(sk);
|
||||
|
||||
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
|
||||
+ goto drop;
|
||||
+
|
||||
if (!net_eq(dev_net(dev), sock_net(sk)))
|
||||
goto drop;
|
||||
|
||||
@@ -2159,12 +2161,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h2)) != 32);
|
||||
BUILD_BUG_ON(TPACKET_ALIGN(sizeof(*h.h3)) != 48);
|
||||
|
||||
- if (skb->pkt_type == PACKET_LOOPBACK)
|
||||
- goto drop;
|
||||
-
|
||||
sk = pt->af_packet_priv;
|
||||
po = pkt_sk(sk);
|
||||
|
||||
+ if (!(po->pkt_type & (1 << skb->pkt_type)))
|
||||
+ goto drop;
|
||||
+
|
||||
if (!net_eq(dev_net(dev), sock_net(sk)))
|
||||
goto drop;
|
||||
|
||||
@@ -3234,6 +3236,7 @@ static int packet_create(struct net *net, struct socket *sock, int protocol,
|
||||
mutex_init(&po->pg_vec_lock);
|
||||
po->rollover = NULL;
|
||||
po->prot_hook.func = packet_rcv;
|
||||
+ po->pkt_type = PACKET_MASK_ANY & ~(1 << PACKET_LOOPBACK);
|
||||
|
||||
if (sock->type == SOCK_PACKET)
|
||||
po->prot_hook.func = packet_rcv_spkt;
|
||||
@@ -3815,6 +3818,16 @@ packet_setsockopt(struct socket *sock, int level, int optname, char __user *optv
|
||||
po->xmit = val ? packet_direct_xmit : dev_queue_xmit;
|
||||
return 0;
|
||||
}
|
||||
+ case PACKET_RECV_TYPE:
|
||||
+ {
|
||||
+ unsigned int val;
|
||||
+ if (optlen != sizeof(val))
|
||||
+ return -EINVAL;
|
||||
+ if (copy_from_user(&val, optval, sizeof(val)))
|
||||
+ return -EFAULT;
|
||||
+ po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
|
||||
+ return 0;
|
||||
+ }
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
@@ -3867,6 +3880,13 @@ static int packet_getsockopt(struct socket *sock, int level, int optname,
|
||||
case PACKET_VNET_HDR:
|
||||
val = po->has_vnet_hdr;
|
||||
break;
|
||||
+ case PACKET_RECV_TYPE:
|
||||
+ if (len > sizeof(unsigned int))
|
||||
+ len = sizeof(unsigned int);
|
||||
+ val = po->pkt_type;
|
||||
+
|
||||
+ data = &val;
|
||||
+ break;
|
||||
case PACKET_VERSION:
|
||||
val = po->tp_version;
|
||||
break;
|
||||
diff --git a/net/packet/internal.h b/net/packet/internal.h
|
||||
index 9ee46314b7d7..76c895fcf22f 100644
|
||||
--- a/net/packet/internal.h
|
||||
+++ b/net/packet/internal.h
|
||||
@@ -129,6 +129,7 @@ struct packet_sock {
|
||||
struct net_device __rcu *cached_dev;
|
||||
int (*xmit)(struct sk_buff *skb);
|
||||
struct packet_type prot_hook ____cacheline_aligned_in_smp;
|
||||
+ unsigned int pkt_type;
|
||||
};
|
||||
|
||||
static struct packet_sock *pkt_sk(struct sock *sk)
|
||||
--
|
||||
2.11.0
|
||||
|
||||
34
target/linux/generic/pending-4.9/650-pppoe_header_pad.patch
Normal file
34
target/linux/generic/pending-4.9/650-pppoe_header_pad.patch
Normal file
@@ -0,0 +1,34 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: pppoe: add extra padding for the header (useful for drivers that need headroom)
|
||||
|
||||
lede-commit 6517a757ec711fc3354b857e273e2621042f3c7a
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/net/ppp/pppoe.c | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/ppp/pppoe.c b/drivers/net/ppp/pppoe.c
|
||||
index 4ddae8118c85..49ef11f92fc9 100644
|
||||
--- a/drivers/net/ppp/pppoe.c
|
||||
+++ b/drivers/net/ppp/pppoe.c
|
||||
@@ -861,7 +861,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
|
||||
goto end;
|
||||
|
||||
|
||||
- skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32,
|
||||
+ skb = sock_wmalloc(sk, total_len + dev->hard_header_len + 32 + NET_SKB_PAD,
|
||||
0, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
error = -ENOMEM;
|
||||
@@ -869,7 +869,7 @@ static int pppoe_sendmsg(struct socket *sock, struct msghdr *m,
|
||||
}
|
||||
|
||||
/* Reserve space for headers. */
|
||||
- skb_reserve(skb, dev->hard_header_len);
|
||||
+ skb_reserve(skb, dev->hard_header_len + NET_SKB_PAD);
|
||||
skb_reset_network_header(skb);
|
||||
|
||||
skb->dev = dev;
|
||||
--
|
||||
2.11.0
|
||||
|
||||
25
target/linux/generic/pending-4.9/655-increase_skb_pad.patch
Normal file
25
target/linux/generic/pending-4.9/655-increase_skb_pad.patch
Normal file
@@ -0,0 +1,25 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add a few patches for avoiding unnecessary skb reallocations - significantly improves ethernet<->wireless performance
|
||||
|
||||
lede-commit: 6f89cffc9add6939d44a6b54cf9a5e77849aa7fd
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/skbuff.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
||||
index 32810f279f8e..5f3343ae25ef 100644
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -2298,7 +2298,7 @@ static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
|
||||
* NET_IP_ALIGN(2) + ethernet_header(14) + IP_header(20/40) + ports(8)
|
||||
*/
|
||||
#ifndef NET_SKB_PAD
|
||||
-#define NET_SKB_PAD max(32, L1_CACHE_BYTES)
|
||||
+#define NET_SKB_PAD max(64, L1_CACHE_BYTES)
|
||||
#endif
|
||||
|
||||
int ___pskb_trim(struct sk_buff *skb, unsigned int len);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,500 @@
|
||||
From: Steven Barth <steven@midlink.org>
|
||||
Subject: Add support for MAP-E FMRs (mesh mode)
|
||||
|
||||
MAP-E FMRs (draft-ietf-softwire-map-10) are rules for IPv4-communication
|
||||
between MAP CEs (mesh mode) without the need to forward such data to a
|
||||
border relay. This is similar to how 6rd works but for IPv4 over IPv6.
|
||||
|
||||
Signed-off-by: Steven Barth <cyrus@openwrt.org>
|
||||
---
|
||||
include/net/ip6_tunnel.h | 13 ++
|
||||
include/uapi/linux/if_tunnel.h | 13 ++
|
||||
net/ipv6/ip6_tunnel.c | 276 +++++++++++++++++++++++++++++++++++++++--
|
||||
3 files changed, 291 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/include/net/ip6_tunnel.h
|
||||
+++ b/include/net/ip6_tunnel.h
|
||||
@@ -17,6 +17,18 @@
|
||||
/* determine capability on a per-packet basis */
|
||||
#define IP6_TNL_F_CAP_PER_PACKET 0x40000
|
||||
|
||||
+/* IPv6 tunnel FMR */
|
||||
+struct __ip6_tnl_fmr {
|
||||
+ struct __ip6_tnl_fmr *next; /* next fmr in list */
|
||||
+ struct in6_addr ip6_prefix;
|
||||
+ struct in_addr ip4_prefix;
|
||||
+
|
||||
+ __u8 ip6_prefix_len;
|
||||
+ __u8 ip4_prefix_len;
|
||||
+ __u8 ea_len;
|
||||
+ __u8 offset;
|
||||
+};
|
||||
+
|
||||
struct __ip6_tnl_parm {
|
||||
char name[IFNAMSIZ]; /* name of tunnel device */
|
||||
int link; /* ifindex of underlying L2 interface */
|
||||
@@ -28,6 +40,7 @@ struct __ip6_tnl_parm {
|
||||
__u32 flags; /* tunnel flags */
|
||||
struct in6_addr laddr; /* local tunnel end-point address */
|
||||
struct in6_addr raddr; /* remote tunnel end-point address */
|
||||
+ struct __ip6_tnl_fmr *fmrs; /* FMRs */
|
||||
|
||||
__be16 i_flags;
|
||||
__be16 o_flags;
|
||||
--- a/include/uapi/linux/if_tunnel.h
|
||||
+++ b/include/uapi/linux/if_tunnel.h
|
||||
@@ -75,10 +75,23 @@ enum {
|
||||
IFLA_IPTUN_ENCAP_SPORT,
|
||||
IFLA_IPTUN_ENCAP_DPORT,
|
||||
IFLA_IPTUN_COLLECT_METADATA,
|
||||
+ IFLA_IPTUN_FMRS,
|
||||
__IFLA_IPTUN_MAX,
|
||||
};
|
||||
#define IFLA_IPTUN_MAX (__IFLA_IPTUN_MAX - 1)
|
||||
|
||||
+enum {
|
||||
+ IFLA_IPTUN_FMR_UNSPEC,
|
||||
+ IFLA_IPTUN_FMR_IP6_PREFIX,
|
||||
+ IFLA_IPTUN_FMR_IP4_PREFIX,
|
||||
+ IFLA_IPTUN_FMR_IP6_PREFIX_LEN,
|
||||
+ IFLA_IPTUN_FMR_IP4_PREFIX_LEN,
|
||||
+ IFLA_IPTUN_FMR_EA_LEN,
|
||||
+ IFLA_IPTUN_FMR_OFFSET,
|
||||
+ __IFLA_IPTUN_FMR_MAX,
|
||||
+};
|
||||
+#define IFLA_IPTUN_FMR_MAX (__IFLA_IPTUN_FMR_MAX - 1)
|
||||
+
|
||||
enum tunnel_encap_types {
|
||||
TUNNEL_ENCAP_NONE,
|
||||
TUNNEL_ENCAP_FOU,
|
||||
--- a/net/ipv6/ip6_tunnel.c
|
||||
+++ b/net/ipv6/ip6_tunnel.c
|
||||
@@ -16,6 +16,8 @@
|
||||
* as published by the Free Software Foundation; either version
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
+ * Changes:
|
||||
+ * Steven Barth <cyrus@openwrt.org>: MAP-E FMR support
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@@ -72,9 +74,9 @@ static bool log_ecn_error = true;
|
||||
module_param(log_ecn_error, bool, 0644);
|
||||
MODULE_PARM_DESC(log_ecn_error, "Log packets received with corrupted ECN");
|
||||
|
||||
-static u32 HASH(const struct in6_addr *addr1, const struct in6_addr *addr2)
|
||||
+static u32 HASH(const struct in6_addr *addr)
|
||||
{
|
||||
- u32 hash = ipv6_addr_hash(addr1) ^ ipv6_addr_hash(addr2);
|
||||
+ u32 hash = ipv6_addr_hash(addr);
|
||||
|
||||
return hash_32(hash, IP6_TUNNEL_HASH_SIZE_SHIFT);
|
||||
}
|
||||
@@ -141,20 +143,29 @@ static struct net_device_stats *ip6_get_
|
||||
static struct ip6_tnl *
|
||||
ip6_tnl_lookup(struct net *net, const struct in6_addr *remote, const struct in6_addr *local)
|
||||
{
|
||||
- unsigned int hash = HASH(remote, local);
|
||||
+ unsigned int hash = HASH(local);
|
||||
struct ip6_tnl *t;
|
||||
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
|
||||
struct in6_addr any;
|
||||
+ struct __ip6_tnl_fmr *fmr;
|
||||
|
||||
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
|
||||
- if (ipv6_addr_equal(local, &t->parms.laddr) &&
|
||||
- ipv6_addr_equal(remote, &t->parms.raddr) &&
|
||||
- (t->dev->flags & IFF_UP))
|
||||
+ if (!ipv6_addr_equal(local, &t->parms.laddr) ||
|
||||
+ !(t->dev->flags & IFF_UP))
|
||||
+ continue;
|
||||
+
|
||||
+ if (ipv6_addr_equal(remote, &t->parms.raddr))
|
||||
return t;
|
||||
+
|
||||
+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
|
||||
+ if (ipv6_prefix_equal(remote, &fmr->ip6_prefix,
|
||||
+ fmr->ip6_prefix_len))
|
||||
+ return t;
|
||||
+ }
|
||||
}
|
||||
|
||||
memset(&any, 0, sizeof(any));
|
||||
- hash = HASH(&any, local);
|
||||
+ hash = HASH(local);
|
||||
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
|
||||
if (ipv6_addr_equal(local, &t->parms.laddr) &&
|
||||
ipv6_addr_any(&t->parms.raddr) &&
|
||||
@@ -162,7 +173,7 @@ ip6_tnl_lookup(struct net *net, const st
|
||||
return t;
|
||||
}
|
||||
|
||||
- hash = HASH(remote, &any);
|
||||
+ hash = HASH(&any);
|
||||
for_each_ip6_tunnel_rcu(ip6n->tnls_r_l[hash]) {
|
||||
if (ipv6_addr_equal(remote, &t->parms.raddr) &&
|
||||
ipv6_addr_any(&t->parms.laddr) &&
|
||||
@@ -202,7 +213,7 @@ ip6_tnl_bucket(struct ip6_tnl_net *ip6n,
|
||||
|
||||
if (!ipv6_addr_any(remote) || !ipv6_addr_any(local)) {
|
||||
prio = 1;
|
||||
- h = HASH(remote, local);
|
||||
+ h = HASH(local);
|
||||
}
|
||||
return &ip6n->tnls[prio][h];
|
||||
}
|
||||
@@ -381,6 +392,12 @@ ip6_tnl_dev_uninit(struct net_device *de
|
||||
struct net *net = t->net;
|
||||
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
|
||||
|
||||
+ while (t->parms.fmrs) {
|
||||
+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
|
||||
+ kfree(t->parms.fmrs);
|
||||
+ t->parms.fmrs = next;
|
||||
+ }
|
||||
+
|
||||
if (dev == ip6n->fb_tnl_dev)
|
||||
RCU_INIT_POINTER(ip6n->tnls_wc[0], NULL);
|
||||
else
|
||||
@@ -777,6 +794,107 @@ int ip6_tnl_rcv_ctl(struct ip6_tnl *t,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ip6_tnl_rcv_ctl);
|
||||
|
||||
+/**
|
||||
+ * ip4ip6_fmr_calc - calculate target / source IPv6-address based on FMR
|
||||
+ * @dest: destination IPv6 address buffer
|
||||
+ * @skb: received socket buffer
|
||||
+ * @fmr: MAP FMR
|
||||
+ * @xmit: Calculate for xmit or rcv
|
||||
+ **/
|
||||
+static void ip4ip6_fmr_calc(struct in6_addr *dest,
|
||||
+ const struct iphdr *iph, const uint8_t *end,
|
||||
+ const struct __ip6_tnl_fmr *fmr, bool xmit)
|
||||
+{
|
||||
+ int psidlen = fmr->ea_len - (32 - fmr->ip4_prefix_len);
|
||||
+ u8 *portp = NULL;
|
||||
+ bool use_dest_addr;
|
||||
+ const struct iphdr *dsth = iph;
|
||||
+
|
||||
+ if ((u8*)dsth >= end)
|
||||
+ return;
|
||||
+
|
||||
+ /* find significant IP header */
|
||||
+ if (iph->protocol == IPPROTO_ICMP) {
|
||||
+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
|
||||
+ if (ih && ((u8*)&ih[1]) <= end && (
|
||||
+ ih->type == ICMP_DEST_UNREACH ||
|
||||
+ ih->type == ICMP_SOURCE_QUENCH ||
|
||||
+ ih->type == ICMP_TIME_EXCEEDED ||
|
||||
+ ih->type == ICMP_PARAMETERPROB ||
|
||||
+ ih->type == ICMP_REDIRECT))
|
||||
+ dsth = (const struct iphdr*)&ih[1];
|
||||
+ }
|
||||
+
|
||||
+ /* in xmit-path use dest port by default and source port only if
|
||||
+ this is an ICMP reply to something else; vice versa in rcv-path */
|
||||
+ use_dest_addr = (xmit && dsth == iph) || (!xmit && dsth != iph);
|
||||
+
|
||||
+ /* get dst port */
|
||||
+ if (((u8*)&dsth[1]) <= end && (
|
||||
+ dsth->protocol == IPPROTO_UDP ||
|
||||
+ dsth->protocol == IPPROTO_TCP ||
|
||||
+ dsth->protocol == IPPROTO_SCTP ||
|
||||
+ dsth->protocol == IPPROTO_DCCP)) {
|
||||
+ /* for UDP, TCP, SCTP and DCCP source and dest port
|
||||
+ follow IPv4 header directly */
|
||||
+ portp = ((u8*)dsth) + dsth->ihl * 4;
|
||||
+
|
||||
+ if (use_dest_addr)
|
||||
+ portp += sizeof(u16);
|
||||
+ } else if (iph->protocol == IPPROTO_ICMP) {
|
||||
+ struct icmphdr *ih = (struct icmphdr*)(((u8*)dsth) + dsth->ihl * 4);
|
||||
+
|
||||
+ /* use icmp identifier as port */
|
||||
+ if (((u8*)&ih) <= end && (
|
||||
+ (use_dest_addr && (
|
||||
+ ih->type == ICMP_ECHOREPLY ||
|
||||
+ ih->type == ICMP_TIMESTAMPREPLY ||
|
||||
+ ih->type == ICMP_INFO_REPLY ||
|
||||
+ ih->type == ICMP_ADDRESSREPLY)) ||
|
||||
+ (!use_dest_addr && (
|
||||
+ ih->type == ICMP_ECHO ||
|
||||
+ ih->type == ICMP_TIMESTAMP ||
|
||||
+ ih->type == ICMP_INFO_REQUEST ||
|
||||
+ ih->type == ICMP_ADDRESS)
|
||||
+ )))
|
||||
+ portp = (u8*)&ih->un.echo.id;
|
||||
+ }
|
||||
+
|
||||
+ if ((portp && &portp[2] <= end) || psidlen == 0) {
|
||||
+ int frombyte = fmr->ip6_prefix_len / 8;
|
||||
+ int fromrem = fmr->ip6_prefix_len % 8;
|
||||
+ int bytes = sizeof(struct in6_addr) - frombyte;
|
||||
+ const u32 *addr = (use_dest_addr) ? &iph->daddr : &iph->saddr;
|
||||
+ u64 eabits = ((u64)ntohl(*addr)) << (32 + fmr->ip4_prefix_len);
|
||||
+ u64 t = 0;
|
||||
+
|
||||
+ /* extract PSID from port and add it to eabits */
|
||||
+ u16 psidbits = 0;
|
||||
+ if (psidlen > 0) {
|
||||
+ psidbits = ((u16)portp[0]) << 8 | ((u16)portp[1]);
|
||||
+ psidbits >>= 16 - psidlen - fmr->offset;
|
||||
+ psidbits = (u16)(psidbits << (16 - psidlen));
|
||||
+ eabits |= ((u64)psidbits) << (48 - (fmr->ea_len - psidlen));
|
||||
+ }
|
||||
+
|
||||
+ /* rewrite destination address */
|
||||
+ *dest = fmr->ip6_prefix;
|
||||
+ memcpy(&dest->s6_addr[10], addr, sizeof(*addr));
|
||||
+ dest->s6_addr16[7] = htons(psidbits >> (16 - psidlen));
|
||||
+
|
||||
+ if (bytes > sizeof(u64))
|
||||
+ bytes = sizeof(u64);
|
||||
+
|
||||
+ /* insert eabits */
|
||||
+ memcpy(&t, &dest->s6_addr[frombyte], bytes);
|
||||
+ t = be64_to_cpu(t) & ~(((((u64)1) << fmr->ea_len) - 1)
|
||||
+ << (64 - fmr->ea_len - fromrem));
|
||||
+ t = cpu_to_be64(t | (eabits >> fromrem));
|
||||
+ memcpy(&dest->s6_addr[frombyte], &t, bytes);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+
|
||||
static int __ip6_tnl_rcv(struct ip6_tnl *tunnel, struct sk_buff *skb,
|
||||
const struct tnl_ptk_info *tpi,
|
||||
struct metadata_dst *tun_dst,
|
||||
@@ -829,6 +947,27 @@ static int __ip6_tnl_rcv(struct ip6_tnl
|
||||
skb_reset_network_header(skb);
|
||||
memset(skb->cb, 0, sizeof(struct inet6_skb_parm));
|
||||
|
||||
+ if (tpi->proto == htons(ETH_P_IP) &&
|
||||
+ !ipv6_addr_equal(&ipv6h->saddr, &tunnel->parms.raddr)) {
|
||||
+ /* Packet didn't come from BR, so lookup FMR */
|
||||
+ struct __ip6_tnl_fmr *fmr;
|
||||
+ struct in6_addr expected = tunnel->parms.raddr;
|
||||
+ for (fmr = tunnel->parms.fmrs; fmr; fmr = fmr->next)
|
||||
+ if (ipv6_prefix_equal(&ipv6h->saddr,
|
||||
+ &fmr->ip6_prefix, fmr->ip6_prefix_len))
|
||||
+ break;
|
||||
+
|
||||
+ /* Check that IPv6 matches IPv4 source to prevent spoofing */
|
||||
+ if (fmr)
|
||||
+ ip4ip6_fmr_calc(&expected, ip_hdr(skb),
|
||||
+ skb_tail_pointer(skb), fmr, false);
|
||||
+
|
||||
+ if (!ipv6_addr_equal(&ipv6h->saddr, &expected)) {
|
||||
+ rcu_read_unlock();
|
||||
+ goto drop;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
__skb_tunnel_rx(skb, tunnel->dev, tunnel->net);
|
||||
|
||||
err = dscp_ecn_decapsulate(tunnel, ipv6h, skb);
|
||||
@@ -958,6 +1097,7 @@ static void init_tel_txopt(struct ipv6_t
|
||||
opt->ops.opt_nflen = 8;
|
||||
}
|
||||
|
||||
+
|
||||
/**
|
||||
* ip6_tnl_addr_conflict - compare packet addresses to tunnel's own
|
||||
* @t: the outgoing tunnel device
|
||||
@@ -1283,6 +1423,7 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
|
||||
{
|
||||
struct ip6_tnl *t = netdev_priv(dev);
|
||||
struct ipv6hdr *ipv6h = ipv6_hdr(skb);
|
||||
+ struct __ip6_tnl_fmr *fmr;
|
||||
int encap_limit = -1;
|
||||
__u16 offset;
|
||||
struct flowi6 fl6;
|
||||
@@ -1338,6 +1479,18 @@ ip6ip6_tnl_xmit(struct sk_buff *skb, str
|
||||
fl6.flowi6_mark = skb->mark;
|
||||
}
|
||||
|
||||
+ /* try to find matching FMR */
|
||||
+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
|
||||
+ unsigned mshift = 32 - fmr->ip4_prefix_len;
|
||||
+ if (ntohl(fmr->ip4_prefix.s_addr) >> mshift ==
|
||||
+ ntohl(ip_hdr(skb)->daddr) >> mshift)
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* change dstaddr according to FMR */
|
||||
+ if (fmr)
|
||||
+ ip4ip6_fmr_calc(&fl6.daddr, ip_hdr(skb), skb_tail_pointer(skb), fmr, true);
|
||||
+
|
||||
if (iptunnel_handle_offloads(skb, SKB_GSO_IPXIP6))
|
||||
return -1;
|
||||
|
||||
@@ -1463,6 +1616,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
|
||||
t->parms.flowinfo = p->flowinfo;
|
||||
t->parms.link = p->link;
|
||||
t->parms.proto = p->proto;
|
||||
+
|
||||
+ while (t->parms.fmrs) {
|
||||
+ struct __ip6_tnl_fmr *next = t->parms.fmrs->next;
|
||||
+ kfree(t->parms.fmrs);
|
||||
+ t->parms.fmrs = next;
|
||||
+ }
|
||||
+ t->parms.fmrs = p->fmrs;
|
||||
+
|
||||
dst_cache_reset(&t->dst_cache);
|
||||
ip6_tnl_link_config(t);
|
||||
return 0;
|
||||
@@ -1501,6 +1662,7 @@ ip6_tnl_parm_from_user(struct __ip6_tnl_
|
||||
p->flowinfo = u->flowinfo;
|
||||
p->link = u->link;
|
||||
p->proto = u->proto;
|
||||
+ p->fmrs = NULL;
|
||||
memcpy(p->name, u->name, sizeof(u->name));
|
||||
}
|
||||
|
||||
@@ -1878,6 +2040,15 @@ static int ip6_tnl_validate(struct nlatt
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const struct nla_policy ip6_tnl_fmr_policy[IFLA_IPTUN_FMR_MAX + 1] = {
|
||||
+ [IFLA_IPTUN_FMR_IP6_PREFIX] = { .len = sizeof(struct in6_addr) },
|
||||
+ [IFLA_IPTUN_FMR_IP4_PREFIX] = { .len = sizeof(struct in_addr) },
|
||||
+ [IFLA_IPTUN_FMR_IP6_PREFIX_LEN] = { .type = NLA_U8 },
|
||||
+ [IFLA_IPTUN_FMR_IP4_PREFIX_LEN] = { .type = NLA_U8 },
|
||||
+ [IFLA_IPTUN_FMR_EA_LEN] = { .type = NLA_U8 },
|
||||
+ [IFLA_IPTUN_FMR_OFFSET] = { .type = NLA_U8 }
|
||||
+};
|
||||
+
|
||||
static void ip6_tnl_netlink_parms(struct nlattr *data[],
|
||||
struct __ip6_tnl_parm *parms)
|
||||
{
|
||||
@@ -1912,6 +2083,46 @@ static void ip6_tnl_netlink_parms(struct
|
||||
|
||||
if (data[IFLA_IPTUN_COLLECT_METADATA])
|
||||
parms->collect_md = true;
|
||||
+
|
||||
+ if (data[IFLA_IPTUN_FMRS]) {
|
||||
+ unsigned rem;
|
||||
+ struct nlattr *fmr;
|
||||
+ nla_for_each_nested(fmr, data[IFLA_IPTUN_FMRS], rem) {
|
||||
+ struct nlattr *fmrd[IFLA_IPTUN_FMR_MAX + 1], *c;
|
||||
+ struct __ip6_tnl_fmr *nfmr;
|
||||
+
|
||||
+ nla_parse_nested(fmrd, IFLA_IPTUN_FMR_MAX,
|
||||
+ fmr, ip6_tnl_fmr_policy);
|
||||
+
|
||||
+ if (!(nfmr = kzalloc(sizeof(*nfmr), GFP_KERNEL)))
|
||||
+ continue;
|
||||
+
|
||||
+ nfmr->offset = 6;
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX]))
|
||||
+ nla_memcpy(&nfmr->ip6_prefix, fmrd[IFLA_IPTUN_FMR_IP6_PREFIX],
|
||||
+ sizeof(nfmr->ip6_prefix));
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX]))
|
||||
+ nla_memcpy(&nfmr->ip4_prefix, fmrd[IFLA_IPTUN_FMR_IP4_PREFIX],
|
||||
+ sizeof(nfmr->ip4_prefix));
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP6_PREFIX_LEN]))
|
||||
+ nfmr->ip6_prefix_len = nla_get_u8(c);
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_IP4_PREFIX_LEN]))
|
||||
+ nfmr->ip4_prefix_len = nla_get_u8(c);
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_EA_LEN]))
|
||||
+ nfmr->ea_len = nla_get_u8(c);
|
||||
+
|
||||
+ if ((c = fmrd[IFLA_IPTUN_FMR_OFFSET]))
|
||||
+ nfmr->offset = nla_get_u8(c);
|
||||
+
|
||||
+ nfmr->next = parms->fmrs;
|
||||
+ parms->fmrs = nfmr;
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
static bool ip6_tnl_netlink_encap_parms(struct nlattr *data[],
|
||||
@@ -2021,6 +2232,12 @@ static void ip6_tnl_dellink(struct net_d
|
||||
|
||||
static size_t ip6_tnl_get_size(const struct net_device *dev)
|
||||
{
|
||||
+ const struct ip6_tnl *t = netdev_priv(dev);
|
||||
+ struct __ip6_tnl_fmr *c;
|
||||
+ int fmrs = 0;
|
||||
+ for (c = t->parms.fmrs; c; c = c->next)
|
||||
+ ++fmrs;
|
||||
+
|
||||
return
|
||||
/* IFLA_IPTUN_LINK */
|
||||
nla_total_size(4) +
|
||||
@@ -2048,6 +2265,24 @@ static size_t ip6_tnl_get_size(const str
|
||||
nla_total_size(2) +
|
||||
/* IFLA_IPTUN_COLLECT_METADATA */
|
||||
nla_total_size(0) +
|
||||
+ /* IFLA_IPTUN_FMRS */
|
||||
+ nla_total_size(0) +
|
||||
+ (
|
||||
+ /* nest */
|
||||
+ nla_total_size(0) +
|
||||
+ /* IFLA_IPTUN_FMR_IP6_PREFIX */
|
||||
+ nla_total_size(sizeof(struct in6_addr)) +
|
||||
+ /* IFLA_IPTUN_FMR_IP4_PREFIX */
|
||||
+ nla_total_size(sizeof(struct in_addr)) +
|
||||
+ /* IFLA_IPTUN_FMR_EA_LEN */
|
||||
+ nla_total_size(1) +
|
||||
+ /* IFLA_IPTUN_FMR_IP6_PREFIX_LEN */
|
||||
+ nla_total_size(1) +
|
||||
+ /* IFLA_IPTUN_FMR_IP4_PREFIX_LEN */
|
||||
+ nla_total_size(1) +
|
||||
+ /* IFLA_IPTUN_FMR_OFFSET */
|
||||
+ nla_total_size(1)
|
||||
+ ) * fmrs +
|
||||
0;
|
||||
}
|
||||
|
||||
@@ -2055,6 +2290,9 @@ static int ip6_tnl_fill_info(struct sk_b
|
||||
{
|
||||
struct ip6_tnl *tunnel = netdev_priv(dev);
|
||||
struct __ip6_tnl_parm *parm = &tunnel->parms;
|
||||
+ struct __ip6_tnl_fmr *c;
|
||||
+ int fmrcnt = 0;
|
||||
+ struct nlattr *fmrs;
|
||||
|
||||
if (nla_put_u32(skb, IFLA_IPTUN_LINK, parm->link) ||
|
||||
nla_put_in6_addr(skb, IFLA_IPTUN_LOCAL, &parm->laddr) ||
|
||||
@@ -2063,9 +2301,27 @@ static int ip6_tnl_fill_info(struct sk_b
|
||||
nla_put_u8(skb, IFLA_IPTUN_ENCAP_LIMIT, parm->encap_limit) ||
|
||||
nla_put_be32(skb, IFLA_IPTUN_FLOWINFO, parm->flowinfo) ||
|
||||
nla_put_u32(skb, IFLA_IPTUN_FLAGS, parm->flags) ||
|
||||
- nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto))
|
||||
+ nla_put_u8(skb, IFLA_IPTUN_PROTO, parm->proto) ||
|
||||
+ !(fmrs = nla_nest_start(skb, IFLA_IPTUN_FMRS)))
|
||||
goto nla_put_failure;
|
||||
|
||||
+ for (c = parm->fmrs; c; c = c->next) {
|
||||
+ struct nlattr *fmr = nla_nest_start(skb, ++fmrcnt);
|
||||
+ if (!fmr ||
|
||||
+ nla_put(skb, IFLA_IPTUN_FMR_IP6_PREFIX,
|
||||
+ sizeof(c->ip6_prefix), &c->ip6_prefix) ||
|
||||
+ nla_put(skb, IFLA_IPTUN_FMR_IP4_PREFIX,
|
||||
+ sizeof(c->ip4_prefix), &c->ip4_prefix) ||
|
||||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP6_PREFIX_LEN, c->ip6_prefix_len) ||
|
||||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_IP4_PREFIX_LEN, c->ip4_prefix_len) ||
|
||||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_EA_LEN, c->ea_len) ||
|
||||
+ nla_put_u8(skb, IFLA_IPTUN_FMR_OFFSET, c->offset))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ nla_nest_end(skb, fmr);
|
||||
+ }
|
||||
+ nla_nest_end(skb, fmrs);
|
||||
+
|
||||
if (nla_put_u16(skb, IFLA_IPTUN_ENCAP_TYPE, tunnel->encap.type) ||
|
||||
nla_put_be16(skb, IFLA_IPTUN_ENCAP_SPORT, tunnel->encap.sport) ||
|
||||
nla_put_be16(skb, IFLA_IPTUN_ENCAP_DPORT, tunnel->encap.dport) ||
|
||||
@@ -2103,6 +2359,7 @@ static const struct nla_policy ip6_tnl_p
|
||||
[IFLA_IPTUN_ENCAP_SPORT] = { .type = NLA_U16 },
|
||||
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
|
||||
[IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
|
||||
+ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static struct rtnl_link_ops ip6_link_ops __read_mostly = {
|
||||
@@ -0,0 +1,247 @@
|
||||
From: Jonas Gorski <jogo@openwrt.org>
|
||||
Subject: ipv6: allow rejecting with "source address failed policy"
|
||||
|
||||
RFC6204 L-14 requires rejecting traffic from invalid addresses with
|
||||
ICMPv6 Destination Unreachable, Code 5 (Source address failed ingress/
|
||||
egress policy) on the LAN side, so add an appropriate rule for that.
|
||||
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
include/net/netns/ipv6.h | 1 +
|
||||
include/uapi/linux/fib_rules.h | 4 +++
|
||||
include/uapi/linux/rtnetlink.h | 1 +
|
||||
net/ipv4/fib_semantics.c | 4 +++
|
||||
net/ipv4/fib_trie.c | 1 +
|
||||
net/ipv4/ipmr.c | 1 +
|
||||
net/ipv6/fib6_rules.c | 4 +++
|
||||
net/ipv6/ip6mr.c | 2 ++
|
||||
net/ipv6/route.c | 58 +++++++++++++++++++++++++++++++++++++++++-
|
||||
9 files changed, 75 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/include/net/netns/ipv6.h
|
||||
+++ b/include/net/netns/ipv6.h
|
||||
@@ -66,6 +66,7 @@ struct netns_ipv6 {
|
||||
unsigned long ip6_rt_last_gc;
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
struct rt6_info *ip6_prohibit_entry;
|
||||
+ struct rt6_info *ip6_policy_failed_entry;
|
||||
struct rt6_info *ip6_blk_hole_entry;
|
||||
struct fib6_table *fib6_local_tbl;
|
||||
struct fib_rules_ops *fib6_rules_ops;
|
||||
--- a/include/uapi/linux/fib_rules.h
|
||||
+++ b/include/uapi/linux/fib_rules.h
|
||||
@@ -66,6 +66,10 @@ enum {
|
||||
FR_ACT_BLACKHOLE, /* Drop without notification */
|
||||
FR_ACT_UNREACHABLE, /* Drop with ENETUNREACH */
|
||||
FR_ACT_PROHIBIT, /* Drop with EACCES */
|
||||
+ FR_ACT_RES9,
|
||||
+ FR_ACT_RES10,
|
||||
+ FR_ACT_RES11,
|
||||
+ FR_ACT_POLICY_FAILED, /* Drop with EACCES */
|
||||
__FR_ACT_MAX,
|
||||
};
|
||||
|
||||
--- a/include/uapi/linux/rtnetlink.h
|
||||
+++ b/include/uapi/linux/rtnetlink.h
|
||||
@@ -215,6 +215,7 @@ enum {
|
||||
RTN_THROW, /* Not in this table */
|
||||
RTN_NAT, /* Translate this address */
|
||||
RTN_XRESOLVE, /* Use external resolver */
|
||||
+ RTN_POLICY_FAILED, /* Failed ingress/egress policy */
|
||||
__RTN_MAX
|
||||
};
|
||||
|
||||
--- a/net/ipv4/fib_semantics.c
|
||||
+++ b/net/ipv4/fib_semantics.c
|
||||
@@ -138,6 +138,10 @@ const struct fib_prop fib_props[RTN_MAX
|
||||
.error = -EINVAL,
|
||||
.scope = RT_SCOPE_NOWHERE,
|
||||
},
|
||||
+ [RTN_POLICY_FAILED] = {
|
||||
+ .error = -EACCES,
|
||||
+ .scope = RT_SCOPE_UNIVERSE,
|
||||
+ },
|
||||
};
|
||||
|
||||
static void rt_fibinfo_free(struct rtable __rcu **rtp)
|
||||
--- a/net/ipv4/fib_trie.c
|
||||
+++ b/net/ipv4/fib_trie.c
|
||||
@@ -2396,6 +2396,7 @@ static const char *const rtn_type_names[
|
||||
[RTN_THROW] = "THROW",
|
||||
[RTN_NAT] = "NAT",
|
||||
[RTN_XRESOLVE] = "XRESOLVE",
|
||||
+ [RTN_POLICY_FAILED] = "POLICY_FAILED",
|
||||
};
|
||||
|
||||
static inline const char *rtn_type(char *buf, size_t len, unsigned int t)
|
||||
--- a/net/ipv4/ipmr.c
|
||||
+++ b/net/ipv4/ipmr.c
|
||||
@@ -157,6 +157,7 @@ static int ipmr_rule_action(struct fib_r
|
||||
case FR_ACT_UNREACHABLE:
|
||||
return -ENETUNREACH;
|
||||
case FR_ACT_PROHIBIT:
|
||||
+ case FR_ACT_POLICY_FAILED:
|
||||
return -EACCES;
|
||||
case FR_ACT_BLACKHOLE:
|
||||
default:
|
||||
--- a/net/ipv6/fib6_rules.c
|
||||
+++ b/net/ipv6/fib6_rules.c
|
||||
@@ -88,6 +88,10 @@ static int fib6_rule_action(struct fib_r
|
||||
err = -EACCES;
|
||||
rt = net->ipv6.ip6_prohibit_entry;
|
||||
goto discard_pkt;
|
||||
+ case FR_ACT_POLICY_FAILED:
|
||||
+ err = -EACCES;
|
||||
+ rt = net->ipv6.ip6_policy_failed_entry;
|
||||
+ goto discard_pkt;
|
||||
}
|
||||
|
||||
tb_id = fib_rule_get_table(rule, arg);
|
||||
--- a/net/ipv6/ip6mr.c
|
||||
+++ b/net/ipv6/ip6mr.c
|
||||
@@ -167,6 +167,8 @@ static int ip6mr_rule_action(struct fib_
|
||||
return -ENETUNREACH;
|
||||
case FR_ACT_PROHIBIT:
|
||||
return -EACCES;
|
||||
+ case FR_ACT_POLICY_FAILED:
|
||||
+ return -EACCES;
|
||||
case FR_ACT_BLACKHOLE:
|
||||
default:
|
||||
return -EINVAL;
|
||||
--- a/net/ipv6/route.c
|
||||
+++ b/net/ipv6/route.c
|
||||
@@ -91,6 +91,8 @@ static int ip6_pkt_discard(struct sk_bu
|
||||
static int ip6_pkt_discard_out(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
static int ip6_pkt_prohibit(struct sk_buff *skb);
|
||||
static int ip6_pkt_prohibit_out(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
+static int ip6_pkt_policy_failed(struct sk_buff *skb);
|
||||
+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||
static void ip6_link_failure(struct sk_buff *skb);
|
||||
static void ip6_rt_update_pmtu(struct dst_entry *dst, struct sock *sk,
|
||||
struct sk_buff *skb, u32 mtu);
|
||||
@@ -300,6 +302,21 @@ static const struct rt6_info ip6_prohibi
|
||||
.rt6i_ref = ATOMIC_INIT(1),
|
||||
};
|
||||
|
||||
+static const struct rt6_info ip6_policy_failed_entry_template = {
|
||||
+ .dst = {
|
||||
+ .__refcnt = ATOMIC_INIT(1),
|
||||
+ .__use = 1,
|
||||
+ .obsolete = DST_OBSOLETE_FORCE_CHK,
|
||||
+ .error = -EACCES,
|
||||
+ .input = ip6_pkt_policy_failed,
|
||||
+ .output = ip6_pkt_policy_failed_out,
|
||||
+ },
|
||||
+ .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
||||
+ .rt6i_protocol = RTPROT_KERNEL,
|
||||
+ .rt6i_metric = ~(u32) 0,
|
||||
+ .rt6i_ref = ATOMIC_INIT(1),
|
||||
+};
|
||||
+
|
||||
static const struct rt6_info ip6_blk_hole_entry_template = {
|
||||
.dst = {
|
||||
.__refcnt = ATOMIC_INIT(1),
|
||||
@@ -1957,6 +1974,11 @@ static struct rt6_info *ip6_route_info_c
|
||||
rt->dst.output = ip6_pkt_prohibit_out;
|
||||
rt->dst.input = ip6_pkt_prohibit;
|
||||
break;
|
||||
+ case RTN_POLICY_FAILED:
|
||||
+ rt->dst.error = -EACCES;
|
||||
+ rt->dst.output = ip6_pkt_policy_failed_out;
|
||||
+ rt->dst.input = ip6_pkt_policy_failed;
|
||||
+ break;
|
||||
case RTN_THROW:
|
||||
case RTN_UNREACHABLE:
|
||||
default:
|
||||
@@ -2600,6 +2622,17 @@ static int ip6_pkt_prohibit_out(struct n
|
||||
return ip6_pkt_drop(skb, ICMPV6_ADM_PROHIBITED, IPSTATS_MIB_OUTNOROUTES);
|
||||
}
|
||||
|
||||
+static int ip6_pkt_policy_failed(struct sk_buff *skb)
|
||||
+{
|
||||
+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_INNOROUTES);
|
||||
+}
|
||||
+
|
||||
+static int ip6_pkt_policy_failed_out(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
+{
|
||||
+ skb->dev = skb_dst(skb)->dev;
|
||||
+ return ip6_pkt_drop(skb, ICMPV6_POLICY_FAIL, IPSTATS_MIB_OUTNOROUTES);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Allocate a dst for local (unicast / anycast) address.
|
||||
*/
|
||||
@@ -2835,7 +2868,8 @@ static int rtm_to_fib6_config(struct sk_
|
||||
if (rtm->rtm_type == RTN_UNREACHABLE ||
|
||||
rtm->rtm_type == RTN_BLACKHOLE ||
|
||||
rtm->rtm_type == RTN_PROHIBIT ||
|
||||
- rtm->rtm_type == RTN_THROW)
|
||||
+ rtm->rtm_type == RTN_THROW ||
|
||||
+ rtm->rtm_type == RTN_POLICY_FAILED)
|
||||
cfg->fc_flags |= RTF_REJECT;
|
||||
|
||||
if (rtm->rtm_type == RTN_LOCAL)
|
||||
@@ -3213,6 +3247,9 @@ static int rt6_fill_node(struct net *net
|
||||
case -EACCES:
|
||||
rtm->rtm_type = RTN_PROHIBIT;
|
||||
break;
|
||||
+ case -EPERM:
|
||||
+ rtm->rtm_type = RTN_POLICY_FAILED;
|
||||
+ break;
|
||||
case -EAGAIN:
|
||||
rtm->rtm_type = RTN_THROW;
|
||||
break;
|
||||
@@ -3489,6 +3526,8 @@ static int ip6_route_dev_notify(struct n
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
net->ipv6.ip6_prohibit_entry->dst.dev = dev;
|
||||
net->ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(dev);
|
||||
+ net->ipv6.ip6_policy_failed_entry->dst.dev = dev;
|
||||
+ net->ipv6.ip6_policy_failed_entry->rt6i_idev = in6_dev_get(dev);
|
||||
net->ipv6.ip6_blk_hole_entry->dst.dev = dev;
|
||||
net->ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(dev);
|
||||
#endif
|
||||
@@ -3711,6 +3750,17 @@ static int __net_init ip6_route_net_init
|
||||
net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
|
||||
dst_init_metrics(&net->ipv6.ip6_blk_hole_entry->dst,
|
||||
ip6_template_metrics, true);
|
||||
+
|
||||
+ net->ipv6.ip6_policy_failed_entry =
|
||||
+ kmemdup(&ip6_policy_failed_entry_template,
|
||||
+ sizeof(*net->ipv6.ip6_policy_failed_entry), GFP_KERNEL);
|
||||
+ if (!net->ipv6.ip6_policy_failed_entry)
|
||||
+ goto out_ip6_blk_hole_entry;
|
||||
+ net->ipv6.ip6_policy_failed_entry->dst.path =
|
||||
+ (struct dst_entry *)net->ipv6.ip6_policy_failed_entry;
|
||||
+ net->ipv6.ip6_policy_failed_entry->dst.ops = &net->ipv6.ip6_dst_ops;
|
||||
+ dst_init_metrics(&net->ipv6.ip6_policy_failed_entry->dst,
|
||||
+ ip6_template_metrics, true);
|
||||
#endif
|
||||
|
||||
net->ipv6.sysctl.flush_delay = 0;
|
||||
@@ -3729,6 +3779,8 @@ out:
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
+out_ip6_blk_hole_entry:
|
||||
+ kfree(net->ipv6.ip6_blk_hole_entry);
|
||||
out_ip6_prohibit_entry:
|
||||
kfree(net->ipv6.ip6_prohibit_entry);
|
||||
out_ip6_null_entry:
|
||||
@@ -3746,6 +3798,7 @@ static void __net_exit ip6_route_net_exi
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
kfree(net->ipv6.ip6_prohibit_entry);
|
||||
kfree(net->ipv6.ip6_blk_hole_entry);
|
||||
+ kfree(net->ipv6.ip6_policy_failed_entry);
|
||||
#endif
|
||||
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
|
||||
}
|
||||
@@ -3819,6 +3872,9 @@ void __init ip6_route_init_special_entri
|
||||
init_net.ipv6.ip6_prohibit_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
||||
init_net.ipv6.ip6_blk_hole_entry->dst.dev = init_net.loopback_dev;
|
||||
init_net.ipv6.ip6_blk_hole_entry->rt6i_idev = in6_dev_get(init_net.loopback_dev);
|
||||
+ init_net.ipv6.ip6_policy_failed_entry->dst.dev = init_net.loopback_dev;
|
||||
+ init_net.ipv6.ip6_policy_failed_entry->rt6i_idev =
|
||||
+ in6_dev_get(init_net.loopback_dev);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
From: Jonas Gorski <jogo@openwrt.org>
|
||||
Subject: net: provide defines for _POLICY_FAILED until all code is updated
|
||||
|
||||
Upstream introduced ICMPV6_POLICY_FAIL for code 5 of destination
|
||||
unreachable, conflicting with our name.
|
||||
|
||||
Add appropriate defines to allow our code to build with the new
|
||||
name until we have updated our local patches for older kernels
|
||||
and userspace packages.
|
||||
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
---
|
||||
include/uapi/linux/fib_rules.h | 2 ++
|
||||
include/uapi/linux/icmpv6.h | 2 ++
|
||||
include/uapi/linux/rtnetlink.h | 2 ++
|
||||
3 files changed, 6 insertions(+)
|
||||
|
||||
--- a/include/uapi/linux/fib_rules.h
|
||||
+++ b/include/uapi/linux/fib_rules.h
|
||||
@@ -73,6 +73,8 @@ enum {
|
||||
__FR_ACT_MAX,
|
||||
};
|
||||
|
||||
+#define FR_ACT_FAILED_POLICY FR_ACT_POLICY_FAILED
|
||||
+
|
||||
#define FR_ACT_MAX (__FR_ACT_MAX - 1)
|
||||
|
||||
#endif
|
||||
--- a/include/uapi/linux/icmpv6.h
|
||||
+++ b/include/uapi/linux/icmpv6.h
|
||||
@@ -118,6 +118,8 @@ struct icmp6hdr {
|
||||
#define ICMPV6_POLICY_FAIL 5
|
||||
#define ICMPV6_REJECT_ROUTE 6
|
||||
|
||||
+#define ICMPV6_FAILED_POLICY ICMPV6_POLICY_FAIL
|
||||
+
|
||||
/*
|
||||
* Codes for Time Exceeded
|
||||
*/
|
||||
--- a/include/uapi/linux/rtnetlink.h
|
||||
+++ b/include/uapi/linux/rtnetlink.h
|
||||
@@ -219,6 +219,8 @@ enum {
|
||||
__RTN_MAX
|
||||
};
|
||||
|
||||
+#define RTN_FAILED_POLICY RTN_POLICY_FAILED
|
||||
+
|
||||
#define RTN_MAX (__RTN_MAX - 1)
|
||||
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: net: replace GRO optimization patch with a new one that supports VLANs/bridges with different MAC addresses
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/netdevice.h | 2 ++
|
||||
include/linux/skbuff.h | 3 ++-
|
||||
net/core/dev.c | 48 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
net/ethernet/eth.c | 18 +++++++++++++++++-
|
||||
4 files changed, 69 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
|
||||
index 780e7171f548..6b738c662bc1 100644
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1749,6 +1749,8 @@ struct net_device {
|
||||
struct netdev_hw_addr_list mc;
|
||||
struct netdev_hw_addr_list dev_addrs;
|
||||
|
||||
+ unsigned char local_addr_mask[MAX_ADDR_LEN];
|
||||
+
|
||||
#ifdef CONFIG_SYSFS
|
||||
struct kset *queues_kset;
|
||||
#endif
|
||||
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
|
||||
index 5f3343ae25ef..3a04baab9b28 100644
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -742,7 +742,8 @@ struct sk_buff {
|
||||
#ifdef CONFIG_NET_SWITCHDEV
|
||||
__u8 offload_fwd_mark:1;
|
||||
#endif
|
||||
- /* 2, 4 or 5 bit hole */
|
||||
+ __u8 gro_skip:1;
|
||||
+ /* 1, 3 or 4 bit hole */
|
||||
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
__u16 tc_index; /* traffic control index */
|
||||
diff --git a/net/core/dev.c b/net/core/dev.c
|
||||
index 2e04fd188081..c7c96308bc84 100644
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -4512,6 +4512,9 @@ static enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff
|
||||
enum gro_result ret;
|
||||
int grow;
|
||||
|
||||
+ if (skb->gro_skip)
|
||||
+ goto normal;
|
||||
+
|
||||
if (!(skb->dev->features & NETIF_F_GRO))
|
||||
goto normal;
|
||||
|
||||
@@ -5789,6 +5792,48 @@ static void __netdev_adjacent_dev_unlink_neighbour(struct net_device *dev,
|
||||
&upper_dev->adj_list.lower);
|
||||
}
|
||||
|
||||
+static void __netdev_addr_mask(unsigned char *mask, const unsigned char *addr,
|
||||
+ struct net_device *dev)
|
||||
+{
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < dev->addr_len; i++)
|
||||
+ mask[i] |= addr[i] ^ dev->dev_addr[i];
|
||||
+}
|
||||
+
|
||||
+static void __netdev_upper_mask(unsigned char *mask, struct net_device *dev,
|
||||
+ struct net_device *lower)
|
||||
+{
|
||||
+ struct net_device *cur;
|
||||
+ struct list_head *iter;
|
||||
+
|
||||
+ netdev_for_each_upper_dev_rcu(dev, cur, iter) {
|
||||
+ __netdev_addr_mask(mask, cur->dev_addr, lower);
|
||||
+ __netdev_upper_mask(mask, cur, lower);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void __netdev_update_addr_mask(struct net_device *dev)
|
||||
+{
|
||||
+ unsigned char mask[MAX_ADDR_LEN];
|
||||
+ struct net_device *cur;
|
||||
+ struct list_head *iter;
|
||||
+
|
||||
+ memset(mask, 0, sizeof(mask));
|
||||
+ __netdev_upper_mask(mask, dev, dev);
|
||||
+ memcpy(dev->local_addr_mask, mask, dev->addr_len);
|
||||
+
|
||||
+ netdev_for_each_lower_dev(dev, cur, iter)
|
||||
+ __netdev_update_addr_mask(cur);
|
||||
+}
|
||||
+
|
||||
+static void netdev_update_addr_mask(struct net_device *dev)
|
||||
+{
|
||||
+ rcu_read_lock();
|
||||
+ __netdev_update_addr_mask(dev);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
static int __netdev_upper_dev_link(struct net_device *dev,
|
||||
struct net_device *upper_dev, bool master,
|
||||
void *upper_priv, void *upper_info)
|
||||
@@ -5987,6 +6032,8 @@ void netdev_upper_dev_unlink(struct net_device *dev,
|
||||
list_for_each_entry(i, &upper_dev->all_adj_list.upper, list)
|
||||
__netdev_adjacent_dev_unlink(dev, i->dev, i->ref_nr);
|
||||
|
||||
+ netdev_update_addr_mask(dev);
|
||||
+ netdev_update_addr_mask(dev);
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER, dev,
|
||||
&changeupper_info.info);
|
||||
}
|
||||
@@ -6587,6 +6634,7 @@ int dev_set_mac_address(struct net_device *dev, struct sockaddr *sa)
|
||||
if (err)
|
||||
return err;
|
||||
dev->addr_assign_type = NET_ADDR_SET;
|
||||
+ netdev_update_addr_mask(dev);
|
||||
call_netdevice_notifiers(NETDEV_CHANGEADDR, dev);
|
||||
add_device_randomness(dev->dev_addr, dev->addr_len);
|
||||
return 0;
|
||||
diff --git a/net/ethernet/eth.c b/net/ethernet/eth.c
|
||||
index fbf1de965a9a..6a6d90b9a880 100644
|
||||
--- a/net/ethernet/eth.c
|
||||
+++ b/net/ethernet/eth.c
|
||||
@@ -143,6 +143,18 @@ u32 eth_get_headlen(void *data, unsigned int len)
|
||||
}
|
||||
EXPORT_SYMBOL(eth_get_headlen);
|
||||
|
||||
+static inline bool
|
||||
+eth_check_local_mask(const void *addr1, const void *addr2, const void *mask)
|
||||
+{
|
||||
+ const u16 *a1 = addr1;
|
||||
+ const u16 *a2 = addr2;
|
||||
+ const u16 *m = mask;
|
||||
+
|
||||
+ return (((a1[0] ^ a2[0]) & ~m[0]) |
|
||||
+ ((a1[1] ^ a2[1]) & ~m[1]) |
|
||||
+ ((a1[2] ^ a2[2]) & ~m[2]));
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* eth_type_trans - determine the packet's protocol ID.
|
||||
* @skb: received socket data
|
||||
@@ -171,8 +183,12 @@ __be16 eth_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
skb->pkt_type = PACKET_MULTICAST;
|
||||
}
|
||||
else if (unlikely(!ether_addr_equal_64bits(eth->h_dest,
|
||||
- dev->dev_addr)))
|
||||
+ dev->dev_addr))) {
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
+ if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
|
||||
+ dev->local_addr_mask))
|
||||
+ skb->gro_skip = 1;
|
||||
+ }
|
||||
|
||||
/*
|
||||
* Some variants of DSA tagging don't have an ethertype field
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
From: John Crispin <blogic@openwrt.org>
|
||||
Subject: NET: add mtd-mac-address support to of_get_mac_address()
|
||||
|
||||
Many embedded devices have information such as mac addresses stored inside mtd
|
||||
devices. This patch allows us to add a property inside a node describing a
|
||||
network interface. The new property points at a mtd partition with an offset
|
||||
where the mac address can be found.
|
||||
|
||||
Signed-off-by: John Crispin <blogic@openwrt.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/of/of_net.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
include/linux/of_net.h | 1 +
|
||||
2 files changed, 38 insertions(+)
|
||||
|
||||
--- a/drivers/of/of_net.c
|
||||
+++ b/drivers/of/of_net.c
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/of_net.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
|
||||
/**
|
||||
* of_get_phy_mode - Get phy mode for given device_node
|
||||
@@ -38,7 +39,7 @@ int of_get_phy_mode(struct device_node *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(of_get_phy_mode);
|
||||
|
||||
-static const void *of_get_mac_addr(struct device_node *np, const char *name)
|
||||
+static void *of_get_mac_addr(struct device_node *np, const char *name)
|
||||
{
|
||||
struct property *pp = of_find_property(np, name, NULL);
|
||||
|
||||
@@ -47,6 +48,73 @@ static const void *of_get_mac_addr(struc
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+static const void *of_get_mac_address_mtd(struct device_node *np)
|
||||
+{
|
||||
+#ifdef CONFIG_MTD
|
||||
+ struct device_node *mtd_np = NULL;
|
||||
+ struct property *prop;
|
||||
+ size_t retlen;
|
||||
+ int size, ret;
|
||||
+ struct mtd_info *mtd;
|
||||
+ const char *part;
|
||||
+ const __be32 *list;
|
||||
+ phandle phandle;
|
||||
+ u32 mac_inc = 0;
|
||||
+ u8 mac[ETH_ALEN];
|
||||
+ void *addr;
|
||||
+
|
||||
+ list = of_get_property(np, "mtd-mac-address", &size);
|
||||
+ if (!list || (size != (2 * sizeof(*list))))
|
||||
+ return NULL;
|
||||
+
|
||||
+ phandle = be32_to_cpup(list++);
|
||||
+ if (phandle)
|
||||
+ mtd_np = of_find_node_by_phandle(phandle);
|
||||
+
|
||||
+ if (!mtd_np)
|
||||
+ return NULL;
|
||||
+
|
||||
+ part = of_get_property(mtd_np, "label", NULL);
|
||||
+ if (!part)
|
||||
+ part = mtd_np->name;
|
||||
+
|
||||
+ mtd = get_mtd_device_nm(part);
|
||||
+ if (IS_ERR(mtd))
|
||||
+ return NULL;
|
||||
+
|
||||
+ ret = mtd_read(mtd, be32_to_cpup(list), 6, &retlen, mac);
|
||||
+ put_mtd_device(mtd);
|
||||
+
|
||||
+ if (!of_property_read_u32(np, "mtd-mac-address-increment", &mac_inc))
|
||||
+ mac[5] += mac_inc;
|
||||
+
|
||||
+ if (!is_valid_ether_addr(mac))
|
||||
+ return NULL;
|
||||
+
|
||||
+ addr = of_get_mac_addr(np, "mac-address");
|
||||
+ if (addr) {
|
||||
+ memcpy(addr, mac, ETH_ALEN);
|
||||
+ return addr;
|
||||
+ }
|
||||
+
|
||||
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
|
||||
+ if (!prop)
|
||||
+ return NULL;
|
||||
+
|
||||
+ prop->name = "mac-address";
|
||||
+ prop->length = ETH_ALEN;
|
||||
+ prop->value = kmemdup(mac, ETH_ALEN, GFP_KERNEL);
|
||||
+ if (!prop->value || of_add_property(np, prop))
|
||||
+ goto free;
|
||||
+
|
||||
+ return prop->value;
|
||||
+free:
|
||||
+ kfree(prop->value);
|
||||
+ kfree(prop);
|
||||
+#endif
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* Search the device tree for the best MAC address to use. 'mac-address' is
|
||||
* checked first, because that is supposed to contain to "most recent" MAC
|
||||
@@ -64,11 +132,18 @@ static const void *of_get_mac_addr(struc
|
||||
* addresses. Some older U-Boots only initialized 'local-mac-address'. In
|
||||
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
|
||||
* but is all zeros.
|
||||
+ *
|
||||
+ * If a mtd-mac-address property exists, try to fetch the MAC address from the
|
||||
+ * specified mtd device, and store it as a 'mac-address' property
|
||||
*/
|
||||
const void *of_get_mac_address(struct device_node *np)
|
||||
{
|
||||
const void *addr;
|
||||
|
||||
+ addr = of_get_mac_address_mtd(np);
|
||||
+ if (addr)
|
||||
+ return addr;
|
||||
+
|
||||
addr = of_get_mac_addr(np, "mac-address");
|
||||
if (addr)
|
||||
return addr;
|
||||
79
target/linux/generic/pending-4.9/701-phy_extension.patch
Normal file
79
target/linux/generic/pending-4.9/701-phy_extension.patch
Normal file
@@ -0,0 +1,79 @@
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Subject: net: phy: add phy_ethtool_ioctl()
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
drivers/net/phy/phy.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 1 +
|
||||
2 files changed, 45 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/phy.c b/drivers/net/phy/phy.c
|
||||
index a9be26f1f677..d0a5ac1d6445 100644
|
||||
--- a/drivers/net/phy/phy.c
|
||||
+++ b/drivers/net/phy/phy.c
|
||||
@@ -466,6 +466,50 @@ int phy_ethtool_ksettings_get(struct phy_device *phydev,
|
||||
}
|
||||
EXPORT_SYMBOL(phy_ethtool_ksettings_get);
|
||||
|
||||
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
|
||||
+{
|
||||
+ u32 cmd;
|
||||
+ int tmp;
|
||||
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
|
||||
+ struct ethtool_value edata = { ETHTOOL_GLINK };
|
||||
+
|
||||
+ if (get_user(cmd, (u32 *) useraddr))
|
||||
+ return -EFAULT;
|
||||
+
|
||||
+ switch (cmd) {
|
||||
+ case ETHTOOL_GSET:
|
||||
+ phy_ethtool_gset(phydev, &ecmd);
|
||||
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
|
||||
+ return -EFAULT;
|
||||
+ return 0;
|
||||
+
|
||||
+ case ETHTOOL_SSET:
|
||||
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
|
||||
+ return -EFAULT;
|
||||
+ return phy_ethtool_sset(phydev, &ecmd);
|
||||
+
|
||||
+ case ETHTOOL_NWAY_RST:
|
||||
+ /* if autoneg is off, it's an error */
|
||||
+ tmp = phy_read(phydev, MII_BMCR);
|
||||
+ if (tmp & BMCR_ANENABLE) {
|
||||
+ tmp |= (BMCR_ANRESTART);
|
||||
+ phy_write(phydev, MII_BMCR, tmp);
|
||||
+ return 0;
|
||||
+ }
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ case ETHTOOL_GLINK:
|
||||
+ edata.data = (phy_read(phydev,
|
||||
+ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
|
||||
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
|
||||
+ return -EFAULT;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -EOPNOTSUPP;
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_ethtool_ioctl);
|
||||
+
|
||||
/**
|
||||
* phy_mii_ioctl - generic PHY MII ioctl interface
|
||||
* @phydev: the phy_device struct
|
||||
diff --git a/include/linux/phy.h b/include/linux/phy.h
|
||||
index bd22670e2182..93c1e74afc44 100644
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -813,6 +813,7 @@ int phy_ethtool_ksettings_get(struct phy_device *phydev,
|
||||
struct ethtool_link_ksettings *cmd);
|
||||
int phy_ethtool_ksettings_set(struct phy_device *phydev,
|
||||
const struct ethtool_link_ksettings *cmd);
|
||||
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
|
||||
int phy_mii_ioctl(struct phy_device *phydev, struct ifreq *ifr, int cmd);
|
||||
int phy_start_interrupts(struct phy_device *phydev);
|
||||
void phy_print_status(struct phy_device *phydev);
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: generic: add detach callback to struct phy_driver
|
||||
|
||||
lede-commit: fe61fc2d7d0b3fb348b502f68f98243b3ddf5867
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 3 +++
|
||||
include/linux/phy.h | 6 ++++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
|
||||
index 14d57d0d1c04..c37d3a27e372 100644
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1001,6 +1001,9 @@ void phy_detach(struct phy_device *phydev)
|
||||
struct mii_bus *bus;
|
||||
int i;
|
||||
|
||||
+ if (phydev->drv && phydev->drv->detach)
|
||||
+ phydev->drv->detach(phydev);
|
||||
+
|
||||
phydev->attached_dev->phydev = NULL;
|
||||
phydev->attached_dev = NULL;
|
||||
phy_suspend(phydev);
|
||||
diff --git a/include/linux/phy.h b/include/linux/phy.h
|
||||
index 93c1e74afc44..d97a418f2cf7 100644
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -508,6 +508,12 @@ struct phy_driver {
|
||||
*/
|
||||
int (*did_interrupt)(struct phy_device *phydev);
|
||||
|
||||
+ /*
|
||||
+ * Called before an ethernet device is detached
|
||||
+ * from the PHY.
|
||||
+ */
|
||||
+ void (*detach)(struct phy_device *phydev);
|
||||
+
|
||||
/* Clears up any memory if needed */
|
||||
void (*remove)(struct phy_device *phydev);
|
||||
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: net: phy: disable soft-reset for generic PHY devices to avoid accidentally clearing preinitialized state
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/drivers/net/phy/phy_device.c b/drivers/net/phy/phy_device.c
|
||||
index c37d3a27e372..069f7ee3e65c 100644
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1482,7 +1482,7 @@ int genphy_config_init(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int gen10g_soft_reset(struct phy_device *phydev)
|
||||
+static int no_soft_reset(struct phy_device *phydev)
|
||||
{
|
||||
/* Do nothing for now */
|
||||
return 0;
|
||||
@@ -1721,7 +1721,7 @@ static struct phy_driver genphy_driver[] = {
|
||||
.phy_id = 0xffffffff,
|
||||
.phy_id_mask = 0xffffffff,
|
||||
.name = "Generic PHY",
|
||||
- .soft_reset = genphy_soft_reset,
|
||||
+ .soft_reset = no_soft_reset,
|
||||
.config_init = genphy_config_init,
|
||||
.features = PHY_GBIT_FEATURES | SUPPORTED_MII |
|
||||
SUPPORTED_AUI | SUPPORTED_FIBRE |
|
||||
@@ -1735,7 +1735,7 @@ static struct phy_driver genphy_driver[] = {
|
||||
.phy_id = 0xffffffff,
|
||||
.phy_id_mask = 0xffffffff,
|
||||
.name = "Generic 10G PHY",
|
||||
- .soft_reset = gen10g_soft_reset,
|
||||
+ .soft_reset = no_soft_reset,
|
||||
.config_init = gen10g_config_init,
|
||||
.features = 0,
|
||||
.config_aneg = gen10g_config_aneg,
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: net: phy: allow to configure AR803x PHYs via platform data
|
||||
|
||||
Add a patch for the at803x phy driver, in order to be able
|
||||
to configure some register settings via platform data.
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 56 ++++++++++++++++++++++++++++++++
|
||||
include/linux/platform_data/phy-at803x.h | 11 +++++++
|
||||
2 files changed, 67 insertions(+)
|
||||
create mode 100644 include/linux/platform_data/phy-at803x.h
|
||||
|
||||
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
|
||||
index c0f45dde60aa..4a55130dcb1c 100644
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -12,12 +12,14 @@
|
||||
*/
|
||||
|
||||
#include <linux/phy.h>
|
||||
+#include <linux/mdio.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/of_gpio.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
+#include <linux/platform_data/phy-at803x.h>
|
||||
|
||||
#define AT803X_INTR_ENABLE 0x12
|
||||
#define AT803X_INTR_ENABLE_AUTONEG_ERR BIT(15)
|
||||
@@ -45,6 +47,11 @@
|
||||
#define AT803X_REG_CHIP_CONFIG 0x1f
|
||||
#define AT803X_BT_BX_REG_SEL 0x8000
|
||||
|
||||
+#define AT803X_PCS_SMART_EEE_CTRL3 0x805D
|
||||
+#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_MASK 0x3
|
||||
+#define AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT 12
|
||||
+#define AT803X_SMART_EEE_CTRL3_LPI_EN BIT(8)
|
||||
+
|
||||
#define AT803X_DEBUG_ADDR 0x1D
|
||||
#define AT803X_DEBUG_DATA 0x1E
|
||||
|
||||
@@ -72,6 +79,7 @@ MODULE_LICENSE("GPL");
|
||||
struct at803x_priv {
|
||||
bool phy_reset:1;
|
||||
struct gpio_desc *gpiod_reset;
|
||||
+ int prev_speed;
|
||||
};
|
||||
|
||||
struct at803x_context {
|
||||
@@ -276,8 +284,16 @@ static int at803x_probe(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void at803x_disable_smarteee(struct phy_device *phydev)
|
||||
+{
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_PCS, AT803X_PCS_SMART_EEE_CTRL3,
|
||||
+ 1 << AT803X_SMART_EEE_CTRL3_LPI_TX_DELAY_SEL_SHIFT);
|
||||
+ phy_write_mmd(phydev, MDIO_MMD_AN, MDIO_AN_EEE_ADV, 0);
|
||||
+}
|
||||
+
|
||||
static int at803x_config_init(struct phy_device *phydev)
|
||||
{
|
||||
+ struct at803x_platform_data *pdata;
|
||||
int ret;
|
||||
|
||||
ret = genphy_config_init(phydev);
|
||||
@@ -298,6 +314,26 @@ static int at803x_config_init(struct phy_device *phydev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ pdata = dev_get_platdata(&phydev->mdio.dev);
|
||||
+ if (pdata) {
|
||||
+ if (pdata->disable_smarteee)
|
||||
+ at803x_disable_smarteee(phydev);
|
||||
+
|
||||
+ if (pdata->enable_rgmii_rx_delay)
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0, 0,
|
||||
+ AT803X_DEBUG_RX_CLK_DLY_EN);
|
||||
+ else
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_0,
|
||||
+ AT803X_DEBUG_RX_CLK_DLY_EN, 0);
|
||||
+
|
||||
+ if (pdata->enable_rgmii_tx_delay)
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
|
||||
+ AT803X_DEBUG_TX_CLK_DLY_EN);
|
||||
+ else
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
|
||||
+ AT803X_DEBUG_TX_CLK_DLY_EN, 0);
|
||||
+ }
|
||||
+
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -335,6 +371,8 @@ static int at803x_config_intr(struct phy_device *phydev)
|
||||
static void at803x_link_change_notify(struct phy_device *phydev)
|
||||
{
|
||||
struct at803x_priv *priv = phydev->priv;
|
||||
+ struct at803x_platform_data *pdata;
|
||||
+ pdata = dev_get_platdata(&phydev->mdio.dev);
|
||||
|
||||
/*
|
||||
* Conduct a hardware reset for AT8030/2 every time a link loss is
|
||||
@@ -363,6 +401,24 @@ static void at803x_link_change_notify(struct phy_device *phydev)
|
||||
} else {
|
||||
priv->phy_reset = false;
|
||||
}
|
||||
+ if (pdata && pdata->fixup_rgmii_tx_delay &&
|
||||
+ phydev->speed != priv->prev_speed) {
|
||||
+ switch (phydev->speed) {
|
||||
+ case SPEED_10:
|
||||
+ case SPEED_100:
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5, 0,
|
||||
+ AT803X_DEBUG_TX_CLK_DLY_EN);
|
||||
+ break;
|
||||
+ case SPEED_1000:
|
||||
+ at803x_debug_reg_mask(phydev, AT803X_DEBUG_REG_5,
|
||||
+ AT803X_DEBUG_TX_CLK_DLY_EN, 0);
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ priv->prev_speed = phydev->speed;
|
||||
+ }
|
||||
}
|
||||
|
||||
static int at803x_aneg_done(struct phy_device *phydev)
|
||||
diff --git a/include/linux/platform_data/phy-at803x.h b/include/linux/platform_data/phy-at803x.h
|
||||
new file mode 100644
|
||||
index 000000000000..a5df74b4f38d
|
||||
--- /dev/null
|
||||
+++ b/include/linux/platform_data/phy-at803x.h
|
||||
@@ -0,0 +1,11 @@
|
||||
+#ifndef _PHY_AT803X_PDATA_H
|
||||
+#define _PHY_AT803X_PDATA_H
|
||||
+
|
||||
+struct at803x_platform_data {
|
||||
+ int disable_smarteee:1;
|
||||
+ int enable_rgmii_tx_delay:1;
|
||||
+ int enable_rgmii_rx_delay:1;
|
||||
+ int fixup_rgmii_tx_delay:1;
|
||||
+};
|
||||
+
|
||||
+#endif /* _PHY_AT803X_PDATA_H */
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
From: Roman Yeryomin <roman@advem.lv>
|
||||
Subject: kernel: add at803x fix for sgmii mode
|
||||
|
||||
Some (possibly broken) bootloaders incorreclty initialize at8033
|
||||
phy. This patch enables sgmii autonegotiation mode.
|
||||
|
||||
[john@phrozen.org: felix added this to his upstream queue]
|
||||
|
||||
Signed-off-by: Roman Yeryomin <roman@advem.lv>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
diff --git a/drivers/net/phy/at803x.c b/drivers/net/phy/at803x.c
|
||||
index 4a55130dcb1c..434efb68bc5d 100644
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -55,6 +55,10 @@
|
||||
#define AT803X_DEBUG_ADDR 0x1D
|
||||
#define AT803X_DEBUG_DATA 0x1E
|
||||
|
||||
+#define AT803X_REG_CHIP_CONFIG 0x1f
|
||||
+#define AT803X_BT_BX_REG_SEL 0x8000
|
||||
+#define AT803X_SGMII_ANEG_EN 0x1000
|
||||
+
|
||||
#define AT803X_MODE_CFG_MASK 0x0F
|
||||
#define AT803X_MODE_CFG_SGMII 0x01
|
||||
|
||||
@@ -295,6 +299,27 @@ static int at803x_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct at803x_platform_data *pdata;
|
||||
int ret;
|
||||
+ u32 v;
|
||||
+
|
||||
+ if (phydev->drv->phy_id == ATH8031_PHY_ID &&
|
||||
+ phydev->interface == PHY_INTERFACE_MODE_SGMII)
|
||||
+ {
|
||||
+ v = phy_read(phydev, AT803X_REG_CHIP_CONFIG);
|
||||
+ /* select SGMII/fiber page */
|
||||
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
|
||||
+ v & ~AT803X_BT_BX_REG_SEL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ /* enable SGMII autonegotiation */
|
||||
+ ret = phy_write(phydev, MII_BMCR, AT803X_SGMII_ANEG_EN);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ /* select copper page */
|
||||
+ ret = phy_write(phydev, AT803X_REG_CHIP_CONFIG,
|
||||
+ v | AT803X_BT_BX_REG_SEL);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
|
||||
ret = genphy_config_init(phydev);
|
||||
if (ret < 0)
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: debloat: add kernel config option to disabling common PCI quirks
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
drivers/pci/Kconfig | 6 ++++++
|
||||
drivers/pci/quirks.c | 6 ++++++
|
||||
2 files changed, 12 insertions(+)
|
||||
|
||||
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
|
||||
index 6555eb78d91c..120fe3921820 100644
|
||||
--- a/drivers/pci/Kconfig
|
||||
+++ b/drivers/pci/Kconfig
|
||||
@@ -71,6 +71,12 @@ config XEN_PCIDEV_FRONTEND
|
||||
The PCI device frontend driver allows the kernel to import arbitrary
|
||||
PCI devices from a PCI backend to support PCI driver domains.
|
||||
|
||||
+config PCI_DISABLE_COMMON_QUIRKS
|
||||
+ bool "PCI disable common quirks"
|
||||
+ depends on PCI
|
||||
+ help
|
||||
+ If you don't know what to do here, say N.
|
||||
+
|
||||
config HT_IRQ
|
||||
bool "Interrupts on hypertransport devices"
|
||||
default y
|
||||
diff --git a/drivers/pci/quirks.c b/drivers/pci/quirks.c
|
||||
index 5d8151b43fbb..cb356e78e743 100644
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -41,6 +41,7 @@ static void quirk_mmio_always_on(struct pci_dev *dev)
|
||||
DECLARE_PCI_FIXUP_CLASS_EARLY(PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_BRIDGE_HOST, 8, quirk_mmio_always_on);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
/* The Mellanox Tavor device gives false positive parity errors
|
||||
* Mark this device with a broken_parity_status, to allow
|
||||
* PCI scanning code to "skip" this now blacklisted device.
|
||||
@@ -3038,6 +3039,7 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f8, quirk_intel_mc_errata);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65f9, quirk_intel_mc_errata);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x65fa, quirk_intel_mc_errata);
|
||||
|
||||
+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
|
||||
|
||||
/*
|
||||
* Ivytown NTB BAR sizes are misreported by the hardware due to an erratum. To
|
||||
@@ -3094,6 +3096,8 @@ static void fixup_debug_report(struct pci_dev *dev, ktime_t calltime,
|
||||
}
|
||||
}
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
/*
|
||||
* Some BIOS implementations leave the Intel GPU interrupts enabled,
|
||||
* even though no one is handling them (f.e. i915 driver is never loaded).
|
||||
@@ -3128,6 +3132,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0102, disable_igfx_irq);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x010a, disable_igfx_irq);
|
||||
DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_INTEL, 0x0152, disable_igfx_irq);
|
||||
|
||||
+#endif /* !CONFIG_PCI_DISABLE_COMMON_QUIRKS */
|
||||
+
|
||||
/*
|
||||
* PCI devices which are on Intel chips can skip the 10ms delay
|
||||
* before entering D3 mode.
|
||||
--
|
||||
2.11.0
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: debloat: disable common USB quirks
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/usb/host/pci-quirks.c | 16 ++++++++++++++++
|
||||
drivers/usb/host/pci-quirks.h | 18 +++++++++++++++++-
|
||||
include/linux/usb/hcd.h | 7 +++++++
|
||||
3 files changed, 40 insertions(+), 1 deletion(-)
|
||||
|
||||
Index: linux-4.9.40/drivers/usb/host/pci-quirks.c
|
||||
===================================================================
|
||||
--- linux-4.9.40.orig/drivers/usb/host/pci-quirks.c
|
||||
+++ linux-4.9.40/drivers/usb/host/pci-quirks.c
|
||||
@@ -106,6 +106,8 @@ struct amd_chipset_type {
|
||||
u8 rev;
|
||||
};
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
static struct amd_chipset_info {
|
||||
struct pci_dev *nb_dev;
|
||||
struct pci_dev *smbus_dev;
|
||||
@@ -503,6 +505,10 @@ void usb_amd_dev_put(void)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_amd_dev_put);
|
||||
|
||||
+#endif /* CONFIG_PCI_DISABLE_COMMON_QUIRKS */
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_USB_UHCI_HCD)
|
||||
+
|
||||
/*
|
||||
* Make sure the controller is completely inactive, unable to
|
||||
* generate interrupts or do DMA.
|
||||
@@ -582,8 +588,17 @@ reset_needed:
|
||||
uhci_reset_hc(pdev, base);
|
||||
return 1;
|
||||
}
|
||||
+#else
|
||||
+int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(uhci_check_and_reset_hc);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
static inline int io_type_enabled(struct pci_dev *pdev, unsigned int mask)
|
||||
{
|
||||
u16 cmd;
|
||||
@@ -1150,3 +1165,4 @@ static void quirk_usb_early_handoff(stru
|
||||
}
|
||||
DECLARE_PCI_FIXUP_CLASS_FINAL(PCI_ANY_ID, PCI_ANY_ID,
|
||||
PCI_CLASS_SERIAL_USB, 8, quirk_usb_early_handoff);
|
||||
+#endif
|
||||
Index: linux-4.9.40/drivers/usb/host/pci-quirks.h
|
||||
===================================================================
|
||||
--- linux-4.9.40.orig/drivers/usb/host/pci-quirks.h
|
||||
+++ linux-4.9.40/drivers/usb/host/pci-quirks.h
|
||||
@@ -4,6 +4,9 @@
|
||||
#ifdef CONFIG_PCI
|
||||
void uhci_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
int uhci_check_and_reset_hc(struct pci_dev *pdev, unsigned long base);
|
||||
+#endif /* CONFIG_PCI */
|
||||
+
|
||||
+#if defined(CONFIG_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
|
||||
int usb_amd_find_chipset_info(void);
|
||||
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
|
||||
bool usb_amd_hang_symptom_quirk(void);
|
||||
@@ -17,12 +20,25 @@ void usb_disable_xhci_ports(struct pci_d
|
||||
void sb800_prefetch(struct device *dev, int on);
|
||||
#else
|
||||
struct pci_dev;
|
||||
+static inline int usb_amd_find_chipset_info(void)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+static inline bool usb_amd_hang_symptom_quirk(void)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
+static inline bool usb_amd_prefetch_quirk(void)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
static inline void usb_amd_quirk_pll_disable(void) {}
|
||||
static inline void usb_amd_quirk_pll_enable(void) {}
|
||||
static inline void usb_asmedia_modifyflowcontrol(struct pci_dev *pdev) {}
|
||||
static inline void usb_amd_dev_put(void) {}
|
||||
static inline void usb_disable_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
static inline void sb800_prefetch(struct device *dev, int on) {}
|
||||
+static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
#endif /* CONFIG_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
Index: linux-4.9.40/include/linux/usb/hcd.h
|
||||
===================================================================
|
||||
--- linux-4.9.40.orig/include/linux/usb/hcd.h
|
||||
+++ linux-4.9.40/include/linux/usb/hcd.h
|
||||
@@ -461,7 +461,14 @@ extern int usb_hcd_pci_probe(struct pci_
|
||||
extern void usb_hcd_pci_remove(struct pci_dev *dev);
|
||||
extern void usb_hcd_pci_shutdown(struct pci_dev *dev);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
extern int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev);
|
||||
+#else
|
||||
+static inline int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *dev)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern const struct dev_pm_ops usb_hcd_pci_pm_ops;
|
||||
@@ -0,0 +1,76 @@
|
||||
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Subject: usb: Remove annoying warning about bogus URB
|
||||
|
||||
When ath9k-htc Wi-Fi dongle is used with generic OHCI controller
|
||||
infinite stream of warnings appears in debug console like this:
|
||||
-------------------------->8----------------------
|
||||
usb 1-1: new full-speed USB device number 2 using ohci-platform
|
||||
usb 1-1: ath9k_htc: Firmware ath9k_htc/htc_9271-1.4.0.fw requested
|
||||
usb 1-1: ath9k_htc: Transferred FW: ath9k_htc/htc_9271-1.4.0.fw, size:
|
||||
51008
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Not tainted
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc2 ]---
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Tainted: G W
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc3 ]---
|
||||
------------[ cut here ]------------
|
||||
-------------------------->8----------------------
|
||||
|
||||
There're some discussions in mailing lists proposing to disable
|
||||
that particular check alltogether and magically all seem to work
|
||||
fine with muted warning.
|
||||
|
||||
Anyways new thread on that regard could be found here:
|
||||
http://lists.infradead.org/pipermail/linux-snps-arc/2016-July/001310.html
|
||||
|
||||
Let's see what comes out of that new discussion, hopefully patching
|
||||
of generic USB stuff won't be required then.
|
||||
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
---
|
||||
drivers/usb/core/urb.c | 5 -----
|
||||
1 file changed, 5 deletions(-)
|
||||
|
||||
--- a/drivers/usb/core/urb.c
|
||||
+++ b/drivers/usb/core/urb.c
|
||||
@@ -321,9 +321,6 @@ EXPORT_SYMBOL_GPL(usb_unanchor_urb);
|
||||
*/
|
||||
int usb_submit_urb(struct urb *urb, gfp_t mem_flags)
|
||||
{
|
||||
- static int pipetypes[4] = {
|
||||
- PIPE_CONTROL, PIPE_ISOCHRONOUS, PIPE_BULK, PIPE_INTERRUPT
|
||||
- };
|
||||
int xfertype, max;
|
||||
struct usb_device *dev;
|
||||
struct usb_host_endpoint *ep;
|
||||
@@ -441,11 +438,6 @@ int usb_submit_urb(struct urb *urb, gfp_
|
||||
* cause problems in HCDs if they get it wrong.
|
||||
*/
|
||||
|
||||
- /* Check that the pipe's type matches the endpoint's type */
|
||||
- if (usb_pipetype(urb->pipe) != pipetypes[xfertype])
|
||||
- dev_WARN(&dev->dev, "BOGUS urb xfer, pipe %x != type %x\n",
|
||||
- usb_pipetype(urb->pipe), pipetypes[xfertype]);
|
||||
-
|
||||
/* Check against a simple/standard policy */
|
||||
allowed = (URB_NO_TRANSFER_DMA_MAP | URB_NO_INTERRUPT | URB_DIR_MASK |
|
||||
URB_FREE_BUFFER);
|
||||
81
target/linux/generic/pending-4.9/831-ledtrig_netdev.patch
Normal file
81
target/linux/generic/pending-4.9/831-ledtrig_netdev.patch
Normal file
@@ -0,0 +1,81 @@
|
||||
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Subject: usb: Remove annoying warning about bogus URB
|
||||
|
||||
When ath9k-htc Wi-Fi dongle is used with generic OHCI controller
|
||||
infinite stream of warnings appears in debug console like this:
|
||||
-------------------------->8----------------------
|
||||
usb 1-1: new full-speed USB device number 2 using ohci-platform
|
||||
usb 1-1: ath9k_htc: Firmware ath9k_htc/htc_9271-1.4.0.fw requested
|
||||
usb 1-1: ath9k_htc: Transferred FW: ath9k_htc/htc_9271-1.4.0.fw, size:
|
||||
51008
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Not tainted
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc2 ]---
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Tainted: G W
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc3 ]---
|
||||
------------[ cut here ]------------
|
||||
-------------------------->8----------------------
|
||||
|
||||
There're some discussions in mailing lists proposing to disable
|
||||
that particular check alltogether and magically all seem to work
|
||||
fine with muted warning.
|
||||
|
||||
Anyways new thread on that regard could be found here:
|
||||
http://lists.infradead.org/pipermail/linux-snps-arc/2016-July/001310.html
|
||||
|
||||
Let's see what comes out of that new discussion, hopefully patching
|
||||
of generic USB stuff won't be required then.
|
||||
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
---
|
||||
drivers/leds/Makefile | 1 +
|
||||
drivers/leds/trigger/Kconfig | 7 +++++++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
|
||||
index 3965070190f5..6273d7e29eab 100644
|
||||
--- a/drivers/leds/Makefile
|
||||
+++ b/drivers/leds/Makefile
|
||||
@@ -77,3 +77,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-dac124s085.o
|
||||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGERS) += trigger/
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
diff --git a/drivers/leds/trigger/Kconfig b/drivers/leds/trigger/Kconfig
|
||||
index 3f9ddb9fafa7..4ec185389324 100644
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -126,4 +126,11 @@ config LEDS_TRIGGER_PANIC
|
||||
a different trigger.
|
||||
If unsure, say Y.
|
||||
|
||||
+config LEDS_TRIGGER_NETDEV
|
||||
+ tristate "LED Netdev Trigger"
|
||||
+ depends on NET && LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This allows LEDs to be controlled by network device activity.
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
endif # LEDS_TRIGGERS
|
||||
--
|
||||
2.11.0
|
||||
|
||||
149
target/linux/generic/pending-4.9/834-ledtrig-libata.patch
Normal file
149
target/linux/generic/pending-4.9/834-ledtrig-libata.patch
Normal file
@@ -0,0 +1,149 @@
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
Subject: libata: add ledtrig support
|
||||
|
||||
This adds a LED trigger for each ATA port indicating disk activity.
|
||||
|
||||
As this is needed only on specific platforms (NAS SoCs and such),
|
||||
these platforms should define ARCH_WANTS_LIBATA_LEDS if there
|
||||
are boards with LED(s) intended to indicate ATA disk activity and
|
||||
need the OS to take care of that.
|
||||
In that way, if not selected, LED trigger support not will be
|
||||
included in libata-core and both, codepaths and structures remain
|
||||
untouched.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
drivers/ata/Kconfig | 16 ++++++++++++++++
|
||||
drivers/ata/libata-core.c | 41 +++++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/libata.h | 9 +++++++++
|
||||
3 files changed, 66 insertions(+)
|
||||
|
||||
--- a/drivers/ata/Kconfig
|
||||
+++ b/drivers/ata/Kconfig
|
||||
@@ -46,6 +46,22 @@ config ATA_VERBOSE_ERROR
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
+config ARCH_WANT_LIBATA_LEDS
|
||||
+ bool
|
||||
+
|
||||
+config ATA_LEDS
|
||||
+ bool "support ATA port LED triggers"
|
||||
+ depends on ARCH_WANT_LIBATA_LEDS
|
||||
+ select NEW_LEDS
|
||||
+ select LEDS_CLASS
|
||||
+ select LEDS_TRIGGERS
|
||||
+ default y
|
||||
+ help
|
||||
+ This option adds a LED trigger for each registered ATA port.
|
||||
+ It is used to drive disk activity leds connected via GPIO.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
config ATA_ACPI
|
||||
bool "ATA ACPI Support"
|
||||
depends on ACPI
|
||||
--- a/drivers/ata/libata-core.c
|
||||
+++ b/drivers/ata/libata-core.c
|
||||
@@ -731,6 +731,19 @@ u64 ata_tf_read_block(const struct ata_t
|
||||
return block;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+#define LIBATA_BLINK_DELAY 20 /* ms */
|
||||
+static inline void ata_led_act(struct ata_port *ap)
|
||||
+{
|
||||
+ unsigned long led_delay = LIBATA_BLINK_DELAY;
|
||||
+
|
||||
+ if (unlikely(!ap->ledtrig))
|
||||
+ return;
|
||||
+
|
||||
+ led_trigger_blink_oneshot(ap->ledtrig, &led_delay, &led_delay, 0);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/**
|
||||
* ata_build_rw_tf - Build ATA taskfile for given read/write request
|
||||
* @tf: Target ATA taskfile
|
||||
@@ -4963,6 +4976,9 @@ struct ata_queued_cmd *ata_qc_new_init(s
|
||||
if (tag < 0)
|
||||
return NULL;
|
||||
}
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ ata_led_act(ap);
|
||||
+#endif
|
||||
|
||||
qc = __ata_qc_from_tag(ap, tag);
|
||||
qc->tag = tag;
|
||||
@@ -5865,6 +5881,9 @@ struct ata_port *ata_port_alloc(struct a
|
||||
ap->stats.unhandled_irq = 1;
|
||||
ap->stats.idle_irq = 1;
|
||||
#endif
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ ap->ledtrig = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
|
||||
+#endif
|
||||
ata_sff_port_init(ap);
|
||||
|
||||
return ap;
|
||||
@@ -5886,6 +5905,12 @@ static void ata_host_release(struct devi
|
||||
|
||||
kfree(ap->pmp_link);
|
||||
kfree(ap->slave_link);
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ if (ap->ledtrig) {
|
||||
+ led_trigger_unregister(ap->ledtrig);
|
||||
+ kfree(ap->ledtrig);
|
||||
+ };
|
||||
+#endif
|
||||
kfree(ap);
|
||||
host->ports[i] = NULL;
|
||||
}
|
||||
@@ -6332,7 +6357,23 @@ int ata_host_register(struct ata_host *h
|
||||
host->ports[i]->print_id = atomic_inc_return(&ata_print_id);
|
||||
host->ports[i]->local_port_no = i + 1;
|
||||
}
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ for (i = 0; i < host->n_ports; i++) {
|
||||
+ if (unlikely(!host->ports[i]->ledtrig))
|
||||
+ continue;
|
||||
|
||||
+ snprintf(host->ports[i]->ledtrig_name,
|
||||
+ sizeof(host->ports[i]->ledtrig_name), "ata%u",
|
||||
+ host->ports[i]->print_id);
|
||||
+
|
||||
+ host->ports[i]->ledtrig->name = host->ports[i]->ledtrig_name;
|
||||
+
|
||||
+ if (led_trigger_register(host->ports[i]->ledtrig)) {
|
||||
+ kfree(host->ports[i]->ledtrig);
|
||||
+ host->ports[i]->ledtrig = NULL;
|
||||
+ }
|
||||
+ }
|
||||
+#endif
|
||||
/* Create associated sysfs transport objects */
|
||||
for (i = 0; i < host->n_ports; i++) {
|
||||
rc = ata_tport_add(host->dev,host->ports[i]);
|
||||
--- a/include/linux/libata.h
|
||||
+++ b/include/linux/libata.h
|
||||
@@ -38,6 +38,9 @@
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/sched.h>
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+#include <linux/leds.h>
|
||||
+#endif
|
||||
|
||||
/*
|
||||
* Define if arch has non-standard setup. This is a _PCI_ standard
|
||||
@@ -883,6 +886,12 @@ struct ata_port {
|
||||
#ifdef CONFIG_ATA_ACPI
|
||||
struct ata_acpi_gtm __acpi_init_gtm; /* use ata_acpi_init_gtm() */
|
||||
#endif
|
||||
+
|
||||
+#ifdef CONFIG_ATA_LEDS
|
||||
+ struct led_trigger *ledtrig;
|
||||
+ char ledtrig_name[8];
|
||||
+#endif
|
||||
+
|
||||
/* owned by EH */
|
||||
u8 sector_buf[ATA_SECT_SIZE] ____cacheline_aligned;
|
||||
};
|
||||
@@ -0,0 +1,47 @@
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Subject: serial: do not accept sysrq characters via serial port
|
||||
|
||||
many embedded boards have a disconnected TTL level serial which can
|
||||
generate some garbage that can lead to spurious false sysrq detects.
|
||||
|
||||
[john@phrozen.org: sent upstream 22.12.2016]
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/serial_core.h | 2 +-
|
||||
lib/Kconfig.debug | 5 +++++
|
||||
2 files changed, 6 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
|
||||
index 344201437017..7e6165bc1cef 100644
|
||||
--- a/include/linux/serial_core.h
|
||||
+++ b/include/linux/serial_core.h
|
||||
@@ -448,7 +448,7 @@ extern void uart_handle_cts_change(struct uart_port *uport,
|
||||
extern void uart_insert_char(struct uart_port *port, unsigned int status,
|
||||
unsigned int overrun, unsigned int ch, unsigned int flag);
|
||||
|
||||
-#ifdef SUPPORT_SYSRQ
|
||||
+#if defined(SUPPORT_SYSRQ) && defined(CONFIG_MAGIC_SYSRQ_SERIAL)
|
||||
static inline int
|
||||
uart_handle_sysrq_char(struct uart_port *port, unsigned int ch)
|
||||
{
|
||||
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
|
||||
index a6c8db1d62f6..062c580cdd68 100644
|
||||
--- a/lib/Kconfig.debug
|
||||
+++ b/lib/Kconfig.debug
|
||||
@@ -397,6 +397,11 @@ config MAGIC_SYSRQ_DEFAULT_ENABLE
|
||||
This may be set to 1 or 0 to enable or disable them all, or
|
||||
to a bitmask as described in Documentation/sysrq.txt.
|
||||
|
||||
+config MAGIC_SYSRQ_SERIAL
|
||||
+ bool "Enable magic SysRq key over serial"
|
||||
+ depends on MAGIC_SYSRQ
|
||||
+ default y
|
||||
+
|
||||
config DEBUG_KERNEL
|
||||
bool "Kernel debugging"
|
||||
help
|
||||
--
|
||||
2.11.0
|
||||
|
||||
78
target/linux/generic/pending-4.9/920-mangle_bootargs.patch
Normal file
78
target/linux/generic/pending-4.9/920-mangle_bootargs.patch
Normal file
@@ -0,0 +1,78 @@
|
||||
From: Imre Kaloz <kaloz@openwrt.org>
|
||||
Subject: init: add CONFIG_MANGLE_BOOTARGS and disable it by default
|
||||
|
||||
Enabling this option renames the bootloader supplied root=
|
||||
and rootfstype= variables, which might have to be know but
|
||||
would break the automatisms OpenWrt uses.
|
||||
|
||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||
---
|
||||
init/Kconfig | 9 +++++++++
|
||||
init/main.c | 24 ++++++++++++++++++++++++
|
||||
2 files changed, 33 insertions(+)
|
||||
|
||||
diff --git a/init/Kconfig b/init/Kconfig
|
||||
index 9063c81b9665..fb66d3ef78e0 100644
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1687,6 +1687,15 @@ config EMBEDDED
|
||||
an embedded system so certain expert options are available
|
||||
for configuration.
|
||||
|
||||
+config MANGLE_BOOTARGS
|
||||
+ bool "Rename offending bootargs"
|
||||
+ depends on EXPERT
|
||||
+ help
|
||||
+ Sometimes the bootloader passed bogus root= and rootfstype=
|
||||
+ parameters to the kernel, and while you want to ignore them,
|
||||
+ you need to know the values f.e. to support dual firmware
|
||||
+ layouts on the flash.
|
||||
+
|
||||
config HAVE_PERF_EVENTS
|
||||
bool
|
||||
help
|
||||
diff --git a/init/main.c b/init/main.c
|
||||
index ae3996ae9bac..3855fa4ffb95 100644
|
||||
--- a/init/main.c
|
||||
+++ b/init/main.c
|
||||
@@ -352,6 +352,29 @@ static inline void setup_nr_cpu_ids(void) { }
|
||||
static inline void smp_prepare_cpus(unsigned int maxcpus) { }
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_MANGLE_BOOTARGS
|
||||
+static void __init mangle_bootargs(char *command_line)
|
||||
+{
|
||||
+ char *rootdev;
|
||||
+ char *rootfs;
|
||||
+
|
||||
+ rootdev = strstr(command_line, "root=/dev/mtdblock");
|
||||
+
|
||||
+ if (rootdev)
|
||||
+ strncpy(rootdev, "mangled_rootblock=", 18);
|
||||
+
|
||||
+ rootfs = strstr(command_line, "rootfstype");
|
||||
+
|
||||
+ if (rootfs)
|
||||
+ strncpy(rootfs, "mangled_fs", 10);
|
||||
+
|
||||
+}
|
||||
+#else
|
||||
+static void __init mangle_bootargs(char *command_line)
|
||||
+{
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* We need to store the untouched command line for future reference.
|
||||
* We also need to store the touched command line since the parameter
|
||||
@@ -504,6 +527,7 @@ asmlinkage __visible void __init start_kernel(void)
|
||||
pr_notice("%s", linux_banner);
|
||||
setup_arch(&command_line);
|
||||
mm_init_cpumask(&init_mm);
|
||||
+ mangle_bootargs(command_line);
|
||||
setup_command_line(command_line);
|
||||
setup_nr_cpu_ids();
|
||||
setup_per_cpu_areas();
|
||||
--
|
||||
2.11.0
|
||||
|
||||
Reference in New Issue
Block a user