Initial commit
This commit is contained in:
@@ -0,0 +1,29 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 22 Oct 2020 22:00:03 +0200
|
||||
Subject: [PATCH] compiler.h: only include asm/rwonce.h for kernel code
|
||||
|
||||
This header file is not in uapi, which makes any user space code that includes
|
||||
linux/compiler.h to fail with the error 'asm/rwonce.h: No such file or directory'
|
||||
|
||||
Fixes: e506ea451254 ("compiler.h: Split {READ,WRITE}_ONCE definitions out into rwonce.h")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/linux/compiler.h
|
||||
+++ b/include/linux/compiler.h
|
||||
@@ -213,6 +213,8 @@ void ftrace_likely_update(struct ftrace_
|
||||
__v; \
|
||||
})
|
||||
|
||||
+#include <asm/rwonce.h>
|
||||
+
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/*
|
||||
@@ -245,6 +247,4 @@ static inline void *offset_to_ptr(const
|
||||
*/
|
||||
#define prevent_tail_call_optimization() mb()
|
||||
|
||||
-#include <asm/rwonce.h>
|
||||
-
|
||||
#endif /* __LINUX_COMPILER_H */
|
||||
@@ -0,0 +1,11 @@
|
||||
--- a/include/uapi/linux/swab.h
|
||||
+++ b/include/uapi/linux/swab.h
|
||||
@@ -3,7 +3,7 @@
|
||||
#define _UAPI_LINUX_SWAB_H
|
||||
|
||||
#include <linux/types.h>
|
||||
-#include <linux/compiler.h>
|
||||
+#include <linux/stddef.h>
|
||||
#include <asm/bitsperlong.h>
|
||||
#include <asm/swab.h>
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 18 Apr 2018 10:50:05 +0200
|
||||
Subject: [PATCH] MIPS: only process negative stack offsets on stack traces
|
||||
|
||||
Fixes endless back traces in cases where the compiler emits a stack
|
||||
pointer increase in a branch delay slot (probably for some form of
|
||||
function return).
|
||||
|
||||
[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low!
|
||||
[ 3.480070] turning off the locking correctness validator.
|
||||
[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0
|
||||
[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000
|
||||
[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f
|
||||
[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000
|
||||
[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000
|
||||
[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000
|
||||
[ 3.532942] ...
|
||||
[ 3.535362] Call Trace:
|
||||
[ 3.537818] [<80010a48>] show_stack+0x58/0x100
|
||||
[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170
|
||||
[ 3.546613] [<80079f90>] save_trace+0xf0/0x110
|
||||
[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c
|
||||
[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08
|
||||
[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c
|
||||
[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78
|
||||
[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/mips/kernel/process.c
|
||||
+++ b/arch/mips/kernel/process.c
|
||||
@@ -380,6 +380,8 @@ static inline int is_sp_move_ins(union m
|
||||
|
||||
if (ip->i_format.opcode == addiu_op ||
|
||||
ip->i_format.opcode == daddiu_op) {
|
||||
+ if (ip->i_format.simmediate > 0)
|
||||
+ return 0;
|
||||
*frame_size = -ip->i_format.simmediate;
|
||||
return 1;
|
||||
}
|
||||
@@ -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
|
||||
@@ -7053,7 +7053,7 @@ static void __ref alloc_node_mem_map(str
|
||||
if (pgdat == NODE_DATA(0)) {
|
||||
mem_map = NODE_DATA(0)->node_mem_map;
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
- mem_map -= offset;
|
||||
+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
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(+)
|
||||
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -682,6 +682,7 @@ static const struct of_device_id spidev_
|
||||
{ .compatible = "lwn,bk4" },
|
||||
{ .compatible = "dh,dhcom-board" },
|
||||
{ .compatible = "menlo,m53cpld" },
|
||||
+ { .compatible = "siliconlabs,si3210" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
@@ -0,0 +1,78 @@
|
||||
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
|
||||
@@ -609,7 +609,8 @@ static int jffs2_rmdir (struct inode *di
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
+static int __jffs2_mknod (struct inode *dir_i, struct dentry *dentry,
|
||||
+ umode_t mode, dev_t rdev, bool whiteout)
|
||||
{
|
||||
struct jffs2_inode_info *f, *dir_f;
|
||||
struct jffs2_sb_info *c;
|
||||
@@ -748,7 +749,11 @@ static int jffs2_mknod (struct inode *di
|
||||
mutex_unlock(&dir_f->sem);
|
||||
jffs2_complete_reservation(c);
|
||||
|
||||
- d_instantiate_new(dentry, inode);
|
||||
+ if (!whiteout)
|
||||
+ d_instantiate_new(dentry, inode);
|
||||
+ else
|
||||
+ unlock_new_inode(inode);
|
||||
+
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
@@ -756,6 +761,17 @@ static int jffs2_mknod (struct inode *di
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int jffs2_mknod (struct inode *dir_i, struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
+{
|
||||
+ return __jffs2_mknod(dir_i, dentry, mode, rdev, false);
|
||||
+}
|
||||
+
|
||||
+static int jffs2_whiteout (struct inode *old_dir, struct dentry *old_dentry)
|
||||
+{
|
||||
+ return __jffs2_mknod(old_dir, old_dentry, S_IFCHR | WHITEOUT_MODE,
|
||||
+ WHITEOUT_DEV, true);
|
||||
+}
|
||||
+
|
||||
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 +782,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 +848,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
|
||||
@@ -779,18 +779,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;
|
||||
@@ -825,7 +838,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));
|
||||
@@ -851,6 +864,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),
|
||||
@@ -882,7 +901,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,20 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: jffs2: add splice ops
|
||||
|
||||
Add splice_read using generic_file_splice_read.
|
||||
Add splice_write using iter_file_splice_write
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/file.c
|
||||
+++ b/fs/jffs2/file.c
|
||||
@@ -53,6 +53,8 @@ const struct file_operations jffs2_file_
|
||||
.open = generic_file_open,
|
||||
.read_iter = generic_file_read_iter,
|
||||
.write_iter = generic_file_write_iter,
|
||||
+ .splice_read = generic_file_splice_read,
|
||||
+ .splice_write = iter_file_splice_write,
|
||||
.unlocked_ioctl=jffs2_ioctl,
|
||||
.mmap = generic_file_readonly_mmap,
|
||||
.fsync = jffs2_fsync,
|
||||
@@ -0,0 +1,45 @@
|
||||
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
|
||||
@@ -195,6 +195,9 @@ static void __br_handle_local_finish(str
|
||||
/* note: already called with rcu_read_lock */
|
||||
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
+
|
||||
+ if (p->state != BR_STATE_DISABLED)
|
||||
__br_handle_local_finish(skb);
|
||||
|
||||
/* return 1 to signal the okfn() was called so it's ok to use the skb */
|
||||
@@ -348,6 +351,17 @@ static rx_handler_result_t br_handle_fra
|
||||
|
||||
forward:
|
||||
switch (p->state) {
|
||||
+ case BR_STATE_DISABLED:
|
||||
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
+ skb->pkt_type = PACKET_HOST;
|
||||
+
|
||||
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
|
||||
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
+ br_handle_local_finish) == 1) {
|
||||
+ return RX_HANDLER_PASS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
case BR_STATE_FORWARDING:
|
||||
case BR_STATE_LEARNING:
|
||||
if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
@@ -0,0 +1,94 @@
|
||||
From: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
Subject: [PATCH 1/2] rtc: rs5c372: support alarms up to 1 week
|
||||
|
||||
The Ricoh R2221x, R2223x, RS5C372, RV5C387A chips can handle 1 week
|
||||
alarms.
|
||||
|
||||
Read the "wday" alarm register and convert it to a date to support up 1
|
||||
week in our driver.
|
||||
|
||||
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
---
|
||||
drivers/rtc/rtc-rs5c372.c | 48 ++++++++++++++++++++++++++++++++++-----
|
||||
1 file changed, 42 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/rtc/rtc-rs5c372.c
|
||||
+++ b/drivers/rtc/rtc-rs5c372.c
|
||||
@@ -393,7 +393,9 @@ static int rs5c_read_alarm(struct device
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct rs5c372 *rs5c = i2c_get_clientdata(client);
|
||||
- int status;
|
||||
+ int status, wday_offs;
|
||||
+ struct rtc_time rtc;
|
||||
+ unsigned long alarm_secs;
|
||||
|
||||
status = rs5c_get_regs(rs5c);
|
||||
if (status < 0)
|
||||
@@ -403,6 +405,30 @@ static int rs5c_read_alarm(struct device
|
||||
t->time.tm_sec = 0;
|
||||
t->time.tm_min = bcd2bin(rs5c->regs[RS5C_REG_ALARM_A_MIN] & 0x7f);
|
||||
t->time.tm_hour = rs5c_reg2hr(rs5c, rs5c->regs[RS5C_REG_ALARM_A_HOURS]);
|
||||
+ t->time.tm_wday = ffs(rs5c->regs[RS5C_REG_ALARM_A_WDAY] & 0x7f) - 1;
|
||||
+
|
||||
+ /* determine the day, month and year based on alarm wday, taking as a
|
||||
+ * reference the current time from the rtc
|
||||
+ */
|
||||
+ status = rs5c372_rtc_read_time(dev, &rtc);
|
||||
+ if (status < 0)
|
||||
+ return status;
|
||||
+
|
||||
+ wday_offs = t->time.tm_wday - rtc.tm_wday;
|
||||
+ alarm_secs = mktime64(rtc.tm_year + 1900,
|
||||
+ rtc.tm_mon + 1,
|
||||
+ rtc.tm_mday + wday_offs,
|
||||
+ t->time.tm_hour,
|
||||
+ t->time.tm_min,
|
||||
+ t->time.tm_sec);
|
||||
+
|
||||
+ if (wday_offs < 0 || (wday_offs == 0 &&
|
||||
+ (t->time.tm_hour < rtc.tm_hour ||
|
||||
+ (t->time.tm_hour == rtc.tm_hour &&
|
||||
+ t->time.tm_min <= rtc.tm_min))))
|
||||
+ alarm_secs += 7 * 86400;
|
||||
+
|
||||
+ rtc_time64_to_tm(alarm_secs, &t->time);
|
||||
|
||||
/* ... and status */
|
||||
t->enabled = !!(rs5c->regs[RS5C_REG_CTRL1] & RS5C_CTRL1_AALE);
|
||||
@@ -417,12 +443,20 @@ static int rs5c_set_alarm(struct device
|
||||
struct rs5c372 *rs5c = i2c_get_clientdata(client);
|
||||
int status, addr, i;
|
||||
unsigned char buf[3];
|
||||
+ struct rtc_time rtc_tm;
|
||||
+ unsigned long rtc_secs, alarm_secs;
|
||||
|
||||
- /* only handle up to 24 hours in the future, like RTC_ALM_SET */
|
||||
- if (t->time.tm_mday != -1
|
||||
- || t->time.tm_mon != -1
|
||||
- || t->time.tm_year != -1)
|
||||
+ /* chip only can handle alarms up to one week in the future*/
|
||||
+ status = rs5c372_rtc_read_time(dev, &rtc_tm);
|
||||
+ if (status)
|
||||
+ return status;
|
||||
+ rtc_secs = rtc_tm_to_time64(&rtc_tm);
|
||||
+ alarm_secs = rtc_tm_to_time64(&t->time);
|
||||
+ if (alarm_secs >= rtc_secs + 7 * 86400) {
|
||||
+ dev_err(dev, "%s: alarm maximum is one week in the future (%d)\n",
|
||||
+ __func__, status);
|
||||
return -EINVAL;
|
||||
+ }
|
||||
|
||||
/* REVISIT: round up tm_sec */
|
||||
|
||||
@@ -443,7 +477,9 @@ static int rs5c_set_alarm(struct device
|
||||
/* set alarm */
|
||||
buf[0] = bin2bcd(t->time.tm_min);
|
||||
buf[1] = rs5c_hr2reg(rs5c, t->time.tm_hour);
|
||||
- buf[2] = 0x7f; /* any/all days */
|
||||
+ /* each bit is the day of the week, 0x7f means all days */
|
||||
+ buf[2] = (t->time.tm_wday >= 0 && t->time.tm_wday < 7) ?
|
||||
+ BIT(t->time.tm_wday) : 0x7f;
|
||||
|
||||
for (i = 0; i < sizeof(buf); i++) {
|
||||
addr = RS5C_ADDR(RS5C_REG_ALARM_A_MIN + i);
|
||||
@@ -0,0 +1,70 @@
|
||||
From: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
Subject: [PATCH 2/2] rtc: rs5c372: let the alarm to be used as wakeup source
|
||||
|
||||
Currently there is no use for the interrupts on the rs5c372 RTC and the
|
||||
wakealarm isn't enabled. There are some devices like NASes which use this
|
||||
RTC to wake up from the power off state when the INTR pin is activated by
|
||||
the alarm clock.
|
||||
|
||||
Enable the alarm and let to be used as a wakeup source.
|
||||
|
||||
Tested on a Buffalo LS421DE NAS.
|
||||
|
||||
Signed-off-by: Daniel González Cabanelas <dgcbueu@gmail.com>
|
||||
---
|
||||
drivers/rtc/rtc-rs5c372.c | 16 ++++++++++++++++
|
||||
1 file changed, 16 insertions(+)
|
||||
|
||||
--- a/drivers/rtc/rtc-rs5c372.c
|
||||
+++ b/drivers/rtc/rtc-rs5c372.c
|
||||
@@ -654,6 +654,7 @@ static int rs5c372_probe(struct i2c_clie
|
||||
int err = 0;
|
||||
int smbus_mode = 0;
|
||||
struct rs5c372 *rs5c372;
|
||||
+ bool rs5c372_can_wakeup_device = false;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
@@ -689,6 +690,12 @@ static int rs5c372_probe(struct i2c_clie
|
||||
else
|
||||
rs5c372->type = id->driver_data;
|
||||
|
||||
+#ifdef CONFIG_OF
|
||||
+ if(of_property_read_bool(client->dev.of_node,
|
||||
+ "wakeup-source"))
|
||||
+ rs5c372_can_wakeup_device = true;
|
||||
+#endif
|
||||
+
|
||||
/* we read registers 0x0f then 0x00-0x0f; skip the first one */
|
||||
rs5c372->regs = &rs5c372->buf[1];
|
||||
rs5c372->smbus = smbus_mode;
|
||||
@@ -722,6 +729,8 @@ static int rs5c372_probe(struct i2c_clie
|
||||
goto exit;
|
||||
}
|
||||
|
||||
+ rs5c372->has_irq = 1;
|
||||
+
|
||||
/* if the oscillator lost power and no other software (like
|
||||
* the bootloader) set it up, do it here.
|
||||
*
|
||||
@@ -748,6 +757,10 @@ static int rs5c372_probe(struct i2c_clie
|
||||
);
|
||||
|
||||
/* REVISIT use client->irq to register alarm irq ... */
|
||||
+ if (rs5c372_can_wakeup_device) {
|
||||
+ device_init_wakeup(&client->dev, true);
|
||||
+ }
|
||||
+
|
||||
rs5c372->rtc = devm_rtc_device_register(&client->dev,
|
||||
rs5c372_driver.driver.name,
|
||||
&rs5c372_rtc_ops, THIS_MODULE);
|
||||
@@ -761,6 +774,9 @@ static int rs5c372_probe(struct i2c_clie
|
||||
if (err)
|
||||
goto exit;
|
||||
|
||||
+ /* the rs5c372 alarm only supports a minute accuracy */
|
||||
+ rs5c372->rtc->uie_unsupported = 1;
|
||||
+
|
||||
return 0;
|
||||
|
||||
exit:
|
||||
@@ -0,0 +1,31 @@
|
||||
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(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -735,11 +735,11 @@ KBUILD_CFLAGS += $(call cc-disable-warni
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
|
||||
-KBUILD_CFLAGS += -O2
|
||||
+KBUILD_CFLAGS += -O2 $(EXTRA_OPTIMIZATION)
|
||||
else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
|
||||
-KBUILD_CFLAGS += -O3
|
||||
+KBUILD_CFLAGS += -O3 $(EXTRA_OPTIMIZATION)
|
||||
else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
-KBUILD_CFLAGS += -Os
|
||||
+KBUILD_CFLAGS += -Os -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
|
||||
endif
|
||||
|
||||
# Tell gcc to never replace conditional load with a non-conditional one
|
||||
@@ -0,0 +1,119 @@
|
||||
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(+)
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1384,6 +1384,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
|
||||
the unaligned access emulation.
|
||||
see arch/parisc/kernel/unaligned.c for reference
|
||||
|
||||
+config KALLSYMS_UNCOMPRESSED
|
||||
+ bool "Keep kallsyms uncompressed"
|
||||
+ depends on KALLSYMS
|
||||
+ help
|
||||
+ Normally kallsyms contains compressed symbols (using a token table),
|
||||
+ reducing the uncompressed kernel image size. Keeping the symbol table
|
||||
+ uncompressed significantly improves the size of this part in compressed
|
||||
+ kernel images.
|
||||
+
|
||||
+ Say N unless you need compressed kernel images to be small.
|
||||
+
|
||||
config HAVE_PCSPKR_PLATFORM
|
||||
bool
|
||||
|
||||
--- a/kernel/kallsyms.c
|
||||
+++ b/kernel/kallsyms.c
|
||||
@@ -77,6 +77,11 @@ static unsigned int kallsyms_expand_symb
|
||||
* For every byte on the compressed symbol data, copy the table
|
||||
* entry for that byte.
|
||||
*/
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ memcpy(result, data + 1, len - 1);
|
||||
+ result += len - 1;
|
||||
+ len = 0;
|
||||
+#endif
|
||||
while (len) {
|
||||
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
|
||||
data++;
|
||||
@@ -109,6 +114,9 @@ tail:
|
||||
*/
|
||||
static char kallsyms_get_symbol_type(unsigned int off)
|
||||
{
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ return kallsyms_names[off + 1];
|
||||
+#endif
|
||||
/*
|
||||
* Get just the first code, look it up in the token table,
|
||||
* and return the first char from this token.
|
||||
--- a/scripts/kallsyms.c
|
||||
+++ b/scripts/kallsyms.c
|
||||
@@ -58,6 +58,7 @@ static struct addr_range percpu_range =
|
||||
static struct sym_entry **table;
|
||||
static unsigned int table_size, table_cnt;
|
||||
static int all_symbols;
|
||||
+static int uncompressed;
|
||||
static int absolute_percpu;
|
||||
static int base_relative;
|
||||
|
||||
@@ -486,6 +487,9 @@ static void write_src(void)
|
||||
|
||||
free(markers);
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return;
|
||||
+
|
||||
output_label("kallsyms_token_table");
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -537,6 +541,9 @@ static unsigned char *find_token(unsigne
|
||||
{
|
||||
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];
|
||||
@@ -609,6 +616,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--) {
|
||||
@@ -773,6 +783,8 @@ int main(int argc, char **argv)
|
||||
absolute_percpu = 1;
|
||||
else if (strcmp(argv[i], "--base-relative") == 0)
|
||||
base_relative = 1;
|
||||
+ else if (strcmp(argv[i], "--uncompressed") == 0)
|
||||
+ uncompressed = 1;
|
||||
else
|
||||
usage();
|
||||
}
|
||||
--- a/scripts/link-vmlinux.sh
|
||||
+++ b/scripts/link-vmlinux.sh
|
||||
@@ -186,6 +186,10 @@ kallsyms()
|
||||
kallsymopt="${kallsymopt} --base-relative"
|
||||
fi
|
||||
|
||||
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
|
||||
+ kallsymopt="${kallsymopt} --uncompressed"
|
||||
+ fi
|
||||
+
|
||||
info KSYMS ${2}
|
||||
${NM} -n ${1} | scripts/kallsyms ${kallsymopt} > ${2}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
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(-)
|
||||
|
||||
--- a/lib/vsprintf.c
|
||||
+++ b/lib/vsprintf.c
|
||||
@@ -983,8 +983,10 @@ char *symbol_string(char *buf, char *end
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
unsigned long value;
|
||||
-#ifdef CONFIG_KALLSYMS
|
||||
char sym[KSYM_SYMBOL_LEN];
|
||||
+#ifndef CONFIG_KALLSYMS
|
||||
+ struct module *mod;
|
||||
+ int len;
|
||||
#endif
|
||||
|
||||
if (fmt[1] == 'R')
|
||||
@@ -1001,8 +1003,14 @@ char *symbol_string(char *buf, char *end
|
||||
|
||||
return string_nocheck(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 const struct printf_spec default_str_spec = {
|
||||
@@ -0,0 +1,30 @@
|
||||
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>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
usr/Makefile | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/usr/Makefile
|
||||
+++ b/usr/Makefile
|
||||
@@ -61,6 +61,8 @@ hostprogs := gen_init_cpio
|
||||
# The dependency list is generated by gen_initramfs.sh -l
|
||||
-include $(obj)/.initramfs_data.cpio.d
|
||||
|
||||
+deps_initramfs := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
|
||||
+
|
||||
# do not try to update files included in initramfs
|
||||
$(deps_initramfs): ;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
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(-)
|
||||
|
||||
--- a/drivers/net/wireless/ti/Kconfig
|
||||
+++ b/drivers/net/wireless/ti/Kconfig
|
||||
@@ -20,7 +20,7 @@ source "drivers/net/wireless/ti/wlcore/K
|
||||
|
||||
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.
|
||||
@@ -0,0 +1,31 @@
|
||||
From c2deb5ef01a0ef09088832744cbace9e239a6ee0 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
|
||||
Date: Sat, 28 Mar 2020 12:11:50 +0100
|
||||
Subject: [PATCH] generic: platform/mikrotik build bits (5.4)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This patch adds platform/mikrotik kernel build bits
|
||||
|
||||
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
|
||||
---
|
||||
drivers/platform/Kconfig | 2 ++
|
||||
drivers/platform/Makefile | 1 +
|
||||
2 files changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/platform/Kconfig
|
||||
+++ b/drivers/platform/Kconfig
|
||||
@@ -13,3 +13,5 @@ source "drivers/platform/chrome/Kconfig"
|
||||
source "drivers/platform/mellanox/Kconfig"
|
||||
|
||||
source "drivers/platform/olpc/Kconfig"
|
||||
+
|
||||
+source "drivers/platform/mikrotik/Kconfig"
|
||||
--- a/drivers/platform/Makefile
|
||||
+++ b/drivers/platform/Makefile
|
||||
@@ -9,3 +9,4 @@ obj-$(CONFIG_MIPS) += mips/
|
||||
obj-$(CONFIG_OLPC_EC) += olpc/
|
||||
obj-$(CONFIG_GOLDFISH) += goldfish/
|
||||
obj-$(CONFIG_CHROME_PLATFORMS) += chrome/
|
||||
+obj-$(CONFIG_MIKROTIK) += mikrotik/
|
||||
@@ -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
|
||||
@@ -1082,9 +1082,6 @@ config FW_ARC
|
||||
config ARCH_MAY_HAVE_PC_FDC
|
||||
bool
|
||||
|
||||
-config BOOT_RAW
|
||||
- bool
|
||||
-
|
||||
config CEVT_BCM1480
|
||||
bool
|
||||
|
||||
@@ -3174,6 +3171,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,22 @@
|
||||
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(-)
|
||||
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -95,7 +95,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
# machines may also. Since BFD is incredibly buggy with respect to
|
||||
# crossformat linking we rely on the elf2ecoff tool for format conversion.
|
||||
#
|
||||
-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
|
||||
+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
371
target/linux/generic/pending-5.10/305-mips_module_reloc.patch
Normal file
371
target/linux/generic/pending-5.10/305-mips_module_reloc.patch
Normal file
@@ -0,0 +1,371 @@
|
||||
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(-)
|
||||
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -98,8 +98,18 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||
cflags-y += -msoft-float
|
||||
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||
+ifdef CONFIG_64BIT
|
||||
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
+else
|
||||
+ ifdef CONFIG_DYNAMIC_FTRACE
|
||||
+ KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||
+ KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||
+ else
|
||||
+ KBUILD_AFLAGS_MODULE += -mno-long-calls
|
||||
+ KBUILD_CFLAGS_MODULE += -mno-long-calls
|
||||
+ endif
|
||||
+endif
|
||||
|
||||
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||
LDFLAGS_vmlinux += --emit-relocs
|
||||
--- a/arch/mips/include/asm/module.h
|
||||
+++ b/arch/mips/include/asm/module.h
|
||||
@@ -12,6 +12,11 @@ struct mod_arch_specific {
|
||||
const struct exception_table_entry *dbe_start;
|
||||
const struct exception_table_entry *dbe_end;
|
||||
struct mips_hi16 *r_mips_hi16_list;
|
||||
+
|
||||
+ void *phys_plt_tbl;
|
||||
+ void *virt_plt_tbl;
|
||||
+ unsigned int phys_plt_offset;
|
||||
+ unsigned int virt_plt_offset;
|
||||
};
|
||||
|
||||
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
|
||||
--- a/arch/mips/kernel/module.c
|
||||
+++ b/arch/mips/kernel/module.c
|
||||
@@ -31,14 +31,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;
|
||||
+}
|
||||
|
||||
static int apply_r_mips_none(struct module *me, u32 *location,
|
||||
u32 base, Elf_Addr v, bool rela)
|
||||
@@ -54,9 +261,40 @@ static int apply_r_mips_32(struct module
|
||||
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(struct module *me, u32 *location,
|
||||
u32 base, Elf_Addr v, bool rela)
|
||||
{
|
||||
+ u32 ofs = base & 0x03ffffff;
|
||||
+
|
||||
if (v % 4) {
|
||||
pr_err("module %s: dangerous R_MIPS_26 relocation\n",
|
||||
me->name);
|
||||
@@ -64,13 +302,17 @@ static int apply_r_mips_26(struct module
|
||||
}
|
||||
|
||||
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) |
|
||||
- ((base + (v >> 2)) & 0x03ffffff);
|
||||
+ ((ofs + (v >> 2)) & 0x03ffffff);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -446,9 +688,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);
|
||||
@@ -0,0 +1,19 @@
|
||||
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(-)
|
||||
|
||||
--- a/arch/mips/include/asm/mach-generic/spaces.h
|
||||
+++ b/arch/mips/include/asm/mach-generic/spaces.h
|
||||
@@ -54,7 +54,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 */
|
||||
22
target/linux/generic/pending-5.10/308-mips32r2_tune.patch
Normal file
22
target/linux/generic/pending-5.10/308-mips32r2_tune.patch
Normal file
@@ -0,0 +1,22 @@
|
||||
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(-)
|
||||
|
||||
--- a/arch/mips/Makefile
|
||||
+++ b/arch/mips/Makefile
|
||||
@@ -174,7 +174,7 @@ cflags-$(CONFIG_CPU_VR41XX) += -march=r4
|
||||
cflags-$(CONFIG_CPU_R4X00) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R1) += -march=mips32 -Wa,--trap
|
||||
-cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -Wa,--trap
|
||||
+cflags-$(CONFIG_CPU_MIPS32_R2) += -march=mips32r2 -mtune=34kc -Wa,--trap
|
||||
cflags-$(CONFIG_CPU_MIPS32_R5) += -march=mips32r5 -Wa,--trap -modd-spreg
|
||||
cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap -modd-spreg
|
||||
cflags-$(CONFIG_CPU_MIPS64_R1) += -march=mips64 -Wa,--trap
|
||||
@@ -0,0 +1,140 @@
|
||||
From 87ec87c2ad615c1a177cd08ef5fa29fc739f6e50 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Sun, 23 Dec 2018 18:06:53 +0100
|
||||
Subject: [PATCH] MIPS: Add CPU option reporting to /proc/cpuinfo
|
||||
|
||||
Many MIPS CPUs have optional CPU features which are not activates for
|
||||
all CPU cores. Print the CPU options which are implemented in the core
|
||||
in /proc/cpuinfo. This makes it possible to see what features are
|
||||
supported and which are not supported. This should cover all standard
|
||||
MIPS extensions, before it only printed information about the main MIPS
|
||||
ASEs.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
arch/mips/kernel/proc.c | 116 ++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 116 insertions(+)
|
||||
|
||||
--- a/arch/mips/kernel/proc.c
|
||||
+++ b/arch/mips/kernel/proc.c
|
||||
@@ -138,6 +138,120 @@ static int show_cpuinfo(struct seq_file
|
||||
seq_printf(m, "micromips kernel\t: %s\n",
|
||||
(read_c0_config3() & MIPS_CONF3_ISA_OE) ? "yes" : "no");
|
||||
}
|
||||
+
|
||||
+ seq_printf(m, "Options implemented\t:");
|
||||
+ if (cpu_has_tlb)
|
||||
+ seq_printf(m, "%s", " tlb");
|
||||
+ if (cpu_has_ftlb)
|
||||
+ seq_printf(m, "%s", " ftlb");
|
||||
+ if (cpu_has_tlbinv)
|
||||
+ seq_printf(m, "%s", " tlbinv");
|
||||
+ if (cpu_has_segments)
|
||||
+ seq_printf(m, "%s", " segments");
|
||||
+ if (cpu_has_rixiex)
|
||||
+ seq_printf(m, "%s", " rixiex");
|
||||
+ if (cpu_has_ldpte)
|
||||
+ seq_printf(m, "%s", " ldpte");
|
||||
+ if (cpu_has_maar)
|
||||
+ seq_printf(m, "%s", " maar");
|
||||
+ if (cpu_has_rw_llb)
|
||||
+ seq_printf(m, "%s", " rw_llb");
|
||||
+ if (cpu_has_4kex)
|
||||
+ seq_printf(m, "%s", " 4kex");
|
||||
+ if (cpu_has_3k_cache)
|
||||
+ seq_printf(m, "%s", " 3k_cache");
|
||||
+ if (cpu_has_4k_cache)
|
||||
+ seq_printf(m, "%s", " 4k_cache");
|
||||
+ if (cpu_has_6k_cache)
|
||||
+ seq_printf(m, "%s", " 6k_cache");
|
||||
+ if (cpu_has_8k_cache)
|
||||
+ seq_printf(m, "%s", " 8k_cache");
|
||||
+ if (cpu_has_tx39_cache)
|
||||
+ seq_printf(m, "%s", " tx39_cache");
|
||||
+ if (cpu_has_octeon_cache)
|
||||
+ seq_printf(m, "%s", " octeon_cache");
|
||||
+ if (cpu_has_fpu)
|
||||
+ seq_printf(m, "%s", " fpu");
|
||||
+ if (cpu_has_32fpr)
|
||||
+ seq_printf(m, "%s", " 32fpr");
|
||||
+ if (cpu_has_cache_cdex_p)
|
||||
+ seq_printf(m, "%s", " cache_cdex_p");
|
||||
+ if (cpu_has_cache_cdex_s)
|
||||
+ seq_printf(m, "%s", " cache_cdex_s");
|
||||
+ if (cpu_has_prefetch)
|
||||
+ seq_printf(m, "%s", " prefetch");
|
||||
+ if (cpu_has_mcheck)
|
||||
+ seq_printf(m, "%s", " mcheck");
|
||||
+ if (cpu_has_ejtag)
|
||||
+ seq_printf(m, "%s", " ejtag");
|
||||
+ if (cpu_has_llsc)
|
||||
+ seq_printf(m, "%s", " llsc");
|
||||
+ if (cpu_has_guestctl0ext)
|
||||
+ seq_printf(m, "%s", " guestctl0ext");
|
||||
+ if (cpu_has_guestctl1)
|
||||
+ seq_printf(m, "%s", " guestctl1");
|
||||
+ if (cpu_has_guestctl2)
|
||||
+ seq_printf(m, "%s", " guestctl2");
|
||||
+ if (cpu_has_guestid)
|
||||
+ seq_printf(m, "%s", " guestid");
|
||||
+ if (cpu_has_drg)
|
||||
+ seq_printf(m, "%s", " drg");
|
||||
+ if (cpu_has_rixi)
|
||||
+ seq_printf(m, "%s", " rixi");
|
||||
+ if (cpu_has_lpa)
|
||||
+ seq_printf(m, "%s", " lpa");
|
||||
+ if (cpu_has_mvh)
|
||||
+ seq_printf(m, "%s", " mvh");
|
||||
+ if (cpu_has_vtag_icache)
|
||||
+ seq_printf(m, "%s", " vtag_icache");
|
||||
+ if (cpu_has_dc_aliases)
|
||||
+ seq_printf(m, "%s", " dc_aliases");
|
||||
+ if (cpu_has_ic_fills_f_dc)
|
||||
+ seq_printf(m, "%s", " ic_fills_f_dc");
|
||||
+ if (cpu_has_pindexed_dcache)
|
||||
+ seq_printf(m, "%s", " pindexed_dcache");
|
||||
+ if (cpu_has_userlocal)
|
||||
+ seq_printf(m, "%s", " userlocal");
|
||||
+ if (cpu_has_nofpuex)
|
||||
+ seq_printf(m, "%s", " nofpuex");
|
||||
+ if (cpu_has_vint)
|
||||
+ seq_printf(m, "%s", " vint");
|
||||
+ if (cpu_has_veic)
|
||||
+ seq_printf(m, "%s", " veic");
|
||||
+ if (cpu_has_inclusive_pcaches)
|
||||
+ seq_printf(m, "%s", " inclusive_pcaches");
|
||||
+ if (cpu_has_perf_cntr_intr_bit)
|
||||
+ seq_printf(m, "%s", " perf_cntr_intr_bit");
|
||||
+ if (cpu_has_ufr)
|
||||
+ seq_printf(m, "%s", " ufr");
|
||||
+ if (cpu_has_fre)
|
||||
+ seq_printf(m, "%s", " fre");
|
||||
+ if (cpu_has_cdmm)
|
||||
+ seq_printf(m, "%s", " cdmm");
|
||||
+ if (cpu_has_small_pages)
|
||||
+ seq_printf(m, "%s", " small_pages");
|
||||
+ if (cpu_has_nan_legacy)
|
||||
+ seq_printf(m, "%s", " nan_legacy");
|
||||
+ if (cpu_has_nan_2008)
|
||||
+ seq_printf(m, "%s", " nan_2008");
|
||||
+ if (cpu_has_ebase_wg)
|
||||
+ seq_printf(m, "%s", " ebase_wg");
|
||||
+ if (cpu_has_badinstr)
|
||||
+ seq_printf(m, "%s", " badinstr");
|
||||
+ if (cpu_has_badinstrp)
|
||||
+ seq_printf(m, "%s", " badinstrp");
|
||||
+ if (cpu_has_contextconfig)
|
||||
+ seq_printf(m, "%s", " contextconfig");
|
||||
+ if (cpu_has_perf)
|
||||
+ seq_printf(m, "%s", " perf");
|
||||
+ if (cpu_has_shared_ftlb_ram)
|
||||
+ seq_printf(m, "%s", " shared_ftlb_ram");
|
||||
+ if (cpu_has_shared_ftlb_entries)
|
||||
+ seq_printf(m, "%s", " shared_ftlb_entries");
|
||||
+ if (cpu_has_mipsmt_pertccounters)
|
||||
+ seq_printf(m, "%s", " mipsmt_pertccounters");
|
||||
+ seq_printf(m, "\n");
|
||||
+
|
||||
seq_printf(m, "shadow register sets\t: %d\n",
|
||||
cpu_data[n].srsets);
|
||||
seq_printf(m, "kscratch registers\t: %d\n",
|
||||
@@ -0,0 +1,22 @@
|
||||
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(+)
|
||||
|
||||
--- a/arch/arm/kernel/module.c
|
||||
+++ b/arch/arm/kernel/module.c
|
||||
@@ -105,6 +105,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
|
||||
return -ENOEXEC;
|
||||
}
|
||||
|
||||
+ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
|
||||
+ ELF_ST_BIND(sym->st_info) == STB_WEAK)
|
||||
+ continue;
|
||||
+
|
||||
loc = dstsec->sh_addr + rel->r_offset;
|
||||
|
||||
switch (ELF32_R_TYPE(rel->r_info)) {
|
||||
@@ -0,0 +1,281 @@
|
||||
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
|
||||
@@ -9,14 +9,11 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/libfdt.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 <linux/uaccess.h>
|
||||
+#include "machine_kexec.h"
|
||||
|
||||
static unsigned long reboot_code_buffer;
|
||||
|
||||
@@ -30,6 +27,101 @@ void (*_crash_smp_send_stop)(void) = NUL
|
||||
void (*_machine_kexec_shutdown)(void) = NULL;
|
||||
void (*_machine_crash_shutdown)(struct pt_regs *regs) = NULL;
|
||||
|
||||
+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 */
|
||||
+ if (copy_from_user(kexec_argv_buf, buf, size))
|
||||
+ pr_warn("kexec command line copy to kernel space failed\n");
|
||||
+
|
||||
+ 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;
|
||||
+}
|
||||
+
|
||||
static void kexec_image_info(const struct kimage *kimage)
|
||||
{
|
||||
unsigned long i;
|
||||
@@ -99,6 +191,18 @@ machine_kexec_prepare(struct kimage *kim
|
||||
#endif
|
||||
|
||||
kexec_image_info(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);
|
||||
@@ -161,7 +265,7 @@ machine_crash_shutdown(struct pt_regs *r
|
||||
void kexec_nonboot_cpu_jump(void)
|
||||
{
|
||||
local_flush_icache_range((unsigned long)relocated_kexec_smp_wait,
|
||||
- reboot_code_buffer + relocate_new_kernel_size);
|
||||
+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
|
||||
|
||||
relocated_kexec_smp_wait(NULL);
|
||||
}
|
||||
@@ -199,7 +303,7 @@ void kexec_reboot(void)
|
||||
* machine_kexec() CPU.
|
||||
*/
|
||||
local_flush_icache_range(reboot_code_buffer,
|
||||
- reboot_code_buffer + relocate_new_kernel_size);
|
||||
+ reboot_code_buffer + KEXEC_RELOCATE_NEW_KERNEL_SIZE);
|
||||
|
||||
do_kexec = (void *)reboot_code_buffer;
|
||||
do_kexec();
|
||||
@@ -212,10 +316,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 =
|
||||
@@ -223,9 +329,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
|
||||
@@ -256,7 +372,7 @@ machine_kexec(struct kimage *image)
|
||||
#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
|
||||
@@ -10,8 +10,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
|
||||
@@ -96,7 +97,7 @@ done:
|
||||
#endif
|
||||
/* jump to kexec_start_address */
|
||||
j s1
|
||||
- END(relocate_new_kernel)
|
||||
+ END(kexec_relocate_new_kernel)
|
||||
|
||||
#ifdef CONFIG_SMP
|
||||
/*
|
||||
@@ -182,9 +183,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,84 @@
|
||||
From bb0c3b0175240bf152fd7c644821a0cf9f77c37c Mon Sep 17 00:00:00 2001
|
||||
From: Evgeniy Didin <Evgeniy.Didin@synopsys.com>
|
||||
Date: Fri, 15 Mar 2019 18:53:38 +0300
|
||||
Subject: [PATCH] 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: Eugeniy Paltsev <Eugeniy.Paltsev@synopsys.com>
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Signed-off-by: Evgeniy Didin <Evgeniy.Didin@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
|
||||
@@ -88,6 +88,16 @@
|
||||
DSP_EARLY_INIT
|
||||
.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
|
||||
@@ -495,6 +495,8 @@ static inline bool uboot_arg_invalid(uns
|
||||
/* We always pass 0 as magic from U-boot */
|
||||
#define UBOOT_MAGIC_VALUE 0
|
||||
|
||||
+extern struct boot_param_header __image_dtb;
|
||||
+
|
||||
void __init handle_uboot_args(void)
|
||||
{
|
||||
bool use_embedded_dtb = true;
|
||||
@@ -533,7 +535,7 @@ void __init handle_uboot_args(void)
|
||||
ignore_uboot_args:
|
||||
|
||||
if (use_embedded_dtb) {
|
||||
- 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
|
||||
@@ -27,6 +27,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
|
||||
@@ -202,7 +202,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,25 @@
|
||||
From 66770a004afe10df11d3902e16eaa0c2c39436bb Mon Sep 17 00:00:00 2001
|
||||
From: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Date: Fri, 24 May 2019 17:56:19 +0200
|
||||
Subject: [PATCH] powerpc: Enable kernel XZ compression option on PPC_85xx
|
||||
|
||||
Enable kernel XZ compression option on PPC_85xx. Tested with
|
||||
simpleImage on TP-Link TL-WDR4900 (Freescale P1014 processor).
|
||||
|
||||
Suggested-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
---
|
||||
arch/powerpc/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/powerpc/Kconfig
|
||||
+++ b/arch/powerpc/Kconfig
|
||||
@@ -214,7 +214,7 @@ config PPC
|
||||
select HAVE_KERNEL_GZIP
|
||||
select HAVE_KERNEL_LZMA if DEFAULT_UIMAGE
|
||||
select HAVE_KERNEL_LZO if DEFAULT_UIMAGE
|
||||
- select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x
|
||||
+ select HAVE_KERNEL_XZ if PPC_BOOK3S || 44x || PPC_85xx
|
||||
select HAVE_KPROBES
|
||||
select HAVE_KPROBES_ON_FTRACE
|
||||
select HAVE_KRETPROBES
|
||||
313
target/linux/generic/pending-5.10/400-mtd-mtdsplit-support.patch
Normal file
313
target/linux/generic/pending-5.10/400-mtd-mtdsplit-support.patch
Normal file
@@ -0,0 +1,313 @@
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -12,6 +12,25 @@ 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"
|
||||
+
|
||||
+source "drivers/mtd/mtdsplit/Kconfig"
|
||||
+
|
||||
+endmenu
|
||||
+
|
||||
config MTD_TESTS
|
||||
tristate "MTD tests support (DANGEROUS)"
|
||||
depends on m
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -15,10 +15,12 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
+#include <linux/magic.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
|
||||
#include "mtdcore.h"
|
||||
+#include "mtdsplit/mtdsplit.h"
|
||||
|
||||
/*
|
||||
* MTD methods which simply translate the effective address and pass through
|
||||
@@ -236,6 +238,146 @@ static int mtd_add_partition_attrs(struc
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static DEFINE_SPINLOCK(part_parser_lock);
|
||||
+static LIST_HEAD(part_parsers);
|
||||
+
|
||||
+static struct mtd_part_parser *mtd_part_parser_get(const char *name)
|
||||
+{
|
||||
+ struct mtd_part_parser *p, *ret = NULL;
|
||||
+
|
||||
+ spin_lock(&part_parser_lock);
|
||||
+
|
||||
+ list_for_each_entry(p, &part_parsers, list)
|
||||
+ if (!strcmp(p->name, name) && try_module_get(p->owner)) {
|
||||
+ ret = p;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock(&part_parser_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
|
||||
+{
|
||||
+ module_put(p->owner);
|
||||
+}
|
||||
+
|
||||
+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;
|
||||
+}
|
||||
+
|
||||
+static 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;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+run_parsers_by_type(struct mtd_info *child, enum mtd_parser_type type)
|
||||
+{
|
||||
+ struct mtd_partition *parts;
|
||||
+ int nr_parts;
|
||||
+ int i;
|
||||
+
|
||||
+ nr_parts = parse_mtd_partitions_by_type(child, 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 += child->part.offset;
|
||||
+
|
||||
+ mtd_add_partition(child->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
|
||||
+#define SPLIT_FIRMWARE_NAME "unused"
|
||||
+#endif
|
||||
+
|
||||
+static void split_firmware(struct mtd_info *master, struct mtd_info *part)
|
||||
+{
|
||||
+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
|
||||
+}
|
||||
+
|
||||
+static void mtd_partition_split(struct mtd_info *master, struct mtd_info *part)
|
||||
+{
|
||||
+ static int rootfs_found = 0;
|
||||
+
|
||||
+ if (rootfs_found)
|
||||
+ return;
|
||||
+
|
||||
+ if (!strcmp(part->name, "rootfs")) {
|
||||
+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
|
||||
+
|
||||
+ rootfs_found = 1;
|
||||
+ }
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
|
||||
+ !strcmp(part->name, SPLIT_FIRMWARE_NAME) &&
|
||||
+ !of_find_property(mtd_get_of_node(part), "compatible", NULL))
|
||||
+ split_firmware(master, part);
|
||||
+}
|
||||
+
|
||||
int mtd_add_partition(struct mtd_info *parent, const char *name,
|
||||
long long offset, long long length)
|
||||
{
|
||||
@@ -274,6 +416,7 @@ int mtd_add_partition(struct mtd_info *p
|
||||
if (ret)
|
||||
goto err_remove_part;
|
||||
|
||||
+ mtd_partition_split(parent, child);
|
||||
mtd_add_partition_attrs(child);
|
||||
|
||||
return 0;
|
||||
@@ -422,6 +565,7 @@ int add_mtd_partitions(struct mtd_info *
|
||||
goto err_del_partitions;
|
||||
}
|
||||
|
||||
+ mtd_partition_split(master, child);
|
||||
mtd_add_partition_attrs(child);
|
||||
|
||||
/* Look for subpartitions */
|
||||
@@ -438,31 +582,6 @@ err_del_partitions:
|
||||
return ret;
|
||||
}
|
||||
|
||||
-static DEFINE_SPINLOCK(part_parser_lock);
|
||||
-static LIST_HEAD(part_parsers);
|
||||
-
|
||||
-static struct mtd_part_parser *mtd_part_parser_get(const char *name)
|
||||
-{
|
||||
- struct mtd_part_parser *p, *ret = NULL;
|
||||
-
|
||||
- spin_lock(&part_parser_lock);
|
||||
-
|
||||
- list_for_each_entry(p, &part_parsers, list)
|
||||
- if (!strcmp(p->name, name) && try_module_get(p->owner)) {
|
||||
- ret = p;
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
- spin_unlock(&part_parser_lock);
|
||||
-
|
||||
- return ret;
|
||||
-}
|
||||
-
|
||||
-static inline void mtd_part_parser_put(const struct mtd_part_parser *p)
|
||||
-{
|
||||
- module_put(p->owner);
|
||||
-}
|
||||
-
|
||||
/*
|
||||
* Many partition parsers just expected the core to kfree() all their data in
|
||||
* one chunk. Do that by default.
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -75,6 +75,12 @@ struct mtd_part_parser_data {
|
||||
* Functions dealing with the various ways of partitioning the space
|
||||
*/
|
||||
|
||||
+enum mtd_parser_type {
|
||||
+ MTD_PARSER_TYPE_DEVICE = 0,
|
||||
+ MTD_PARSER_TYPE_ROOTFS,
|
||||
+ MTD_PARSER_TYPE_FIRMWARE,
|
||||
+};
|
||||
+
|
||||
struct mtd_part_parser {
|
||||
struct list_head list;
|
||||
struct module *owner;
|
||||
@@ -83,6 +89,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 */
|
||||
--- a/drivers/mtd/Makefile
|
||||
+++ b/drivers/mtd/Makefile
|
||||
@@ -9,6 +9,8 @@ mtd-y := mtdcore.o mtdsuper.o mtdconc
|
||||
|
||||
obj-y += parsers/
|
||||
|
||||
+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
|
||||
+
|
||||
# 'Users' - code which presents functionality to userspace.
|
||||
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
|
||||
obj-$(CONFIG_MTD_BLOCK) += mtdblock.o
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -608,6 +608,24 @@ static inline void mtd_align_erase_req(s
|
||||
req->len += mtd->erasesize - mod;
|
||||
}
|
||||
|
||||
+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)
|
||||
@@ -680,6 +698,13 @@ extern void __put_mtd_device(struct mtd_
|
||||
extern struct mtd_info *get_mtd_device_nm(const char *name);
|
||||
extern void put_mtd_device(struct mtd_info *mtd);
|
||||
|
||||
+static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
|
||||
+{
|
||||
+ if (!mtd_is_partition(mtd))
|
||||
+ return 0;
|
||||
+
|
||||
+ return mtd->part.offset;
|
||||
+}
|
||||
|
||||
struct mtd_notifier {
|
||||
void (*add)(struct mtd_info *mtd);
|
||||
@@ -0,0 +1,76 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Thu, 6 May 2021 12:33:58 +0200
|
||||
Subject: [PATCH] mtd: parsers: ofpart: fix parsing subpartitions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
ofpart was recently patched to not scan random partition nodes as
|
||||
subpartitions. That change unfortunately broke scanning valid
|
||||
subpartitions like:
|
||||
|
||||
partitions {
|
||||
compatible = "fixed-partitions";
|
||||
#address-cells = <1>;
|
||||
#size-cells = <1>;
|
||||
|
||||
partition@0 {
|
||||
compatible = "fixed-partitions";
|
||||
label = "bootloader";
|
||||
reg = <0x0 0x100000>;
|
||||
|
||||
partition@0 {
|
||||
label = "config";
|
||||
reg = <0x80000 0x80000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
Fix that regression by adding 1 more code path. We actually need 3
|
||||
conditional blocks to support 3 possible cases. This change also makes
|
||||
code easier to understand & follow.
|
||||
|
||||
Reported-by: David Bauer <mail@david-bauer.net>
|
||||
Fixes: 2d751203aacf ("mtd: parsers: ofpart: limit parsing of deprecated DT syntax
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
drivers/mtd/parsers/ofpart_core.c | 26 ++++++++++++++------------
|
||||
1 file changed, 14 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/parsers/ofpart_core.c
|
||||
+++ b/drivers/mtd/parsers/ofpart_core.c
|
||||
@@ -57,20 +57,22 @@ static int parse_fixed_partitions(struct
|
||||
if (!mtd_node)
|
||||
return 0;
|
||||
|
||||
- ofpart_node = of_get_child_by_name(mtd_node, "partitions");
|
||||
- if (!ofpart_node && !master->parent) {
|
||||
- /*
|
||||
- * We might get here even when ofpart isn't used at all (e.g.,
|
||||
- * when using another parser), so don't be louder than
|
||||
- * KERN_DEBUG
|
||||
- */
|
||||
- pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
|
||||
- master->name, mtd_node);
|
||||
+ if (!master->parent) { /* Master */
|
||||
+ ofpart_node = of_get_child_by_name(mtd_node, "partitions");
|
||||
+ if (!ofpart_node) {
|
||||
+ /*
|
||||
+ * We might get here even when ofpart isn't used at all (e.g.,
|
||||
+ * when using another parser), so don't be louder than
|
||||
+ * KERN_DEBUG
|
||||
+ */
|
||||
+ pr_debug("%s: 'partitions' subnode not found on %pOF. Trying to parse direct subnodes as partitions.\n",
|
||||
+ master->name, mtd_node);
|
||||
+ ofpart_node = mtd_node;
|
||||
+ dedicated = false;
|
||||
+ }
|
||||
+ } else { /* Partition */
|
||||
ofpart_node = mtd_node;
|
||||
- dedicated = false;
|
||||
}
|
||||
- if (!ofpart_node)
|
||||
- return 0;
|
||||
|
||||
of_id = of_match_node(parse_ofpart_match_table, ofpart_node);
|
||||
if (dedicated && !of_id) {
|
||||
@@ -0,0 +1,22 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] mtd: redboot: add of_match_table with DT binding
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This allows parsing RedBoot compatible partitions for properly described
|
||||
flash device in DT.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/mtd/parsers/redboot.c
|
||||
+++ b/drivers/mtd/parsers/redboot.c
|
||||
@@ -305,6 +305,7 @@ static int parse_redboot_partitions(stru
|
||||
|
||||
static const struct of_device_id mtd_parser_redboot_of_match_table[] = {
|
||||
{ .compatible = "redboot-fis" },
|
||||
+ { .compatible = "ecoscentric,redboot-fis-partitions" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtd_parser_redboot_of_match_table);
|
||||
@@ -0,0 +1,41 @@
|
||||
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(-)
|
||||
|
||||
--- a/drivers/mtd/parsers/redboot.c
|
||||
+++ b/drivers/mtd/parsers/redboot.c
|
||||
@@ -279,14 +279,21 @@ static int parse_redboot_partitions(stru
|
||||
#endif
|
||||
names += strlen(names)+1;
|
||||
|
||||
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
|
||||
- i++;
|
||||
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||
- parts[i].name = nullname;
|
||||
- }
|
||||
+ if (!strcmp(parts[i].name, "rootfs")) {
|
||||
+ parts[i].size = fl->next->img->flash_base;
|
||||
+ parts[i].size &= ~(master->erasesize - 1);
|
||||
+ parts[i].size -= parts[i].offset;
|
||||
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||
+ nrparts--;
|
||||
+ } else {
|
||||
+ i++;
|
||||
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||
+ parts[i].name = nullname;
|
||||
#endif
|
||||
+ }
|
||||
+ }
|
||||
tmp_fl = fl;
|
||||
fl = fl->next;
|
||||
kfree(tmp_fl);
|
||||
@@ -0,0 +1,229 @@
|
||||
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>
|
||||
[adjust for kernel 5.4, add myloader.c to patch]
|
||||
Signed-off-by: Adrian Schmutzler <freifunk@adrianschmutzler.de>
|
||||
|
||||
--- a/drivers/mtd/parsers/Kconfig
|
||||
+++ b/drivers/mtd/parsers/Kconfig
|
||||
@@ -57,6 +57,22 @@ config MTD_CMDLINE_PARTS
|
||||
|
||||
If unsure, say 'N'.
|
||||
|
||||
+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.
|
||||
+
|
||||
config MTD_OF_PARTS
|
||||
tristate "OpenFirmware (device tree) partitioning parser"
|
||||
default y
|
||||
--- a/drivers/mtd/parsers/Makefile
|
||||
+++ b/drivers/mtd/parsers/Makefile
|
||||
@@ -3,6 +3,7 @@ obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.
|
||||
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
|
||||
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
|
||||
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
|
||||
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
|
||||
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
|
||||
ofpart-y += ofpart_core.o
|
||||
ofpart-$(CONFIG_MTD_OF_PARTS_BCM4908) += ofpart_bcm4908.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/parsers/myloader.c
|
||||
@@ -0,0 +1,181 @@
|
||||
+/*
|
||||
+ * Parse MyLoader-style flash partition tables and produce a Linux partition
|
||||
+ * array to match.
|
||||
+ *
|
||||
+ * Copyright (C) 2007-2009 Gabor Juhos <juhosg@openwrt.org>
|
||||
+ *
|
||||
+ * This file was based on drivers/mtd/redboot.c
|
||||
+ * Author: Red Hat, Inc. - David Woodhouse <dwmw2@cambridge.redhat.com>
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify it
|
||||
+ * under the terms of the GNU General Public License version 2 as published
|
||||
+ * by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/version.h>
|
||||
+#include <linux/slab.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/vmalloc.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/byteorder/generic.h>
|
||||
+#include <linux/myloader.h>
|
||||
+
|
||||
+#define BLOCK_LEN_MIN 0x10000
|
||||
+#define PART_NAME_LEN 32
|
||||
+
|
||||
+struct part_data {
|
||||
+ struct mylo_partition_table tab;
|
||||
+ char names[MYLO_MAX_PARTITIONS][PART_NAME_LEN];
|
||||
+};
|
||||
+
|
||||
+static int myloader_parse_partitions(struct mtd_info *master,
|
||||
+ const struct mtd_partition **pparts,
|
||||
+ struct mtd_part_parser_data *data)
|
||||
+{
|
||||
+ struct part_data *buf;
|
||||
+ struct mylo_partition_table *tab;
|
||||
+ struct mylo_partition *part;
|
||||
+ struct mtd_partition *mtd_parts;
|
||||
+ struct mtd_partition *mtd_part;
|
||||
+ int num_parts;
|
||||
+ int ret, i;
|
||||
+ size_t retlen;
|
||||
+ char *names;
|
||||
+ unsigned long offset;
|
||||
+ unsigned long blocklen;
|
||||
+
|
||||
+ buf = vmalloc(sizeof(*buf));
|
||||
+ if (!buf) {
|
||||
+ return -ENOMEM;
|
||||
+ goto out;
|
||||
+ }
|
||||
+ tab = &buf->tab;
|
||||
+
|
||||
+ blocklen = master->erasesize;
|
||||
+ if (blocklen < BLOCK_LEN_MIN)
|
||||
+ blocklen = BLOCK_LEN_MIN;
|
||||
+
|
||||
+ offset = blocklen;
|
||||
+
|
||||
+ /* Find the partition table */
|
||||
+ for (i = 0; i < 4; i++, offset += blocklen) {
|
||||
+ printk(KERN_DEBUG "%s: searching for MyLoader partition table"
|
||||
+ " at offset 0x%lx\n", master->name, offset);
|
||||
+
|
||||
+ ret = mtd_read(master, offset, sizeof(*buf), &retlen,
|
||||
+ (void *)buf);
|
||||
+ if (ret)
|
||||
+ goto out_free_buf;
|
||||
+
|
||||
+ if (retlen != sizeof(*buf)) {
|
||||
+ ret = -EIO;
|
||||
+ goto out_free_buf;
|
||||
+ }
|
||||
+
|
||||
+ /* Check for Partition Table magic number */
|
||||
+ if (tab->magic == le32_to_cpu(MYLO_MAGIC_PARTITIONS))
|
||||
+ break;
|
||||
+
|
||||
+ }
|
||||
+
|
||||
+ if (tab->magic != le32_to_cpu(MYLO_MAGIC_PARTITIONS)) {
|
||||
+ printk(KERN_DEBUG "%s: no MyLoader partition table found\n",
|
||||
+ master->name);
|
||||
+ ret = 0;
|
||||
+ goto out_free_buf;
|
||||
+ }
|
||||
+
|
||||
+ /* The MyLoader and the Partition Table is always present */
|
||||
+ num_parts = 2;
|
||||
+
|
||||
+ /* Detect number of used partitions */
|
||||
+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
|
||||
+ part = &tab->partitions[i];
|
||||
+
|
||||
+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
|
||||
+ continue;
|
||||
+
|
||||
+ num_parts++;
|
||||
+ }
|
||||
+
|
||||
+ mtd_parts = kzalloc((num_parts * sizeof(*mtd_part) +
|
||||
+ num_parts * PART_NAME_LEN), GFP_KERNEL);
|
||||
+
|
||||
+ if (!mtd_parts) {
|
||||
+ ret = -ENOMEM;
|
||||
+ goto out_free_buf;
|
||||
+ }
|
||||
+
|
||||
+ mtd_part = mtd_parts;
|
||||
+ names = (char *)&mtd_parts[num_parts];
|
||||
+
|
||||
+ strncpy(names, "myloader", PART_NAME_LEN);
|
||||
+ mtd_part->name = names;
|
||||
+ mtd_part->offset = 0;
|
||||
+ mtd_part->size = offset;
|
||||
+ mtd_part->mask_flags = MTD_WRITEABLE;
|
||||
+ mtd_part++;
|
||||
+ names += PART_NAME_LEN;
|
||||
+
|
||||
+ strncpy(names, "partition_table", PART_NAME_LEN);
|
||||
+ mtd_part->name = names;
|
||||
+ mtd_part->offset = offset;
|
||||
+ mtd_part->size = blocklen;
|
||||
+ mtd_part->mask_flags = MTD_WRITEABLE;
|
||||
+ mtd_part++;
|
||||
+ names += PART_NAME_LEN;
|
||||
+
|
||||
+ for (i = 0; i < MYLO_MAX_PARTITIONS; i++) {
|
||||
+ part = &tab->partitions[i];
|
||||
+
|
||||
+ if (le16_to_cpu(part->type) == PARTITION_TYPE_FREE)
|
||||
+ continue;
|
||||
+
|
||||
+ if ((buf->names[i][0]) && (buf->names[i][0] != '\xff'))
|
||||
+ strncpy(names, buf->names[i], PART_NAME_LEN);
|
||||
+ else
|
||||
+ snprintf(names, PART_NAME_LEN, "partition%d", i);
|
||||
+
|
||||
+ mtd_part->offset = le32_to_cpu(part->addr);
|
||||
+ mtd_part->size = le32_to_cpu(part->size);
|
||||
+ mtd_part->name = names;
|
||||
+ mtd_part++;
|
||||
+ names += PART_NAME_LEN;
|
||||
+ }
|
||||
+
|
||||
+ *pparts = mtd_parts;
|
||||
+ ret = num_parts;
|
||||
+
|
||||
+ out_free_buf:
|
||||
+ vfree(buf);
|
||||
+ out:
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static struct mtd_part_parser myloader_mtd_parser = {
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .parse_fn = myloader_parse_partitions,
|
||||
+ .name = "MyLoader",
|
||||
+};
|
||||
+
|
||||
+static int __init myloader_mtd_parser_init(void)
|
||||
+{
|
||||
+ register_mtd_parser(&myloader_mtd_parser);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void __exit myloader_mtd_parser_exit(void)
|
||||
+{
|
||||
+ deregister_mtd_parser(&myloader_mtd_parser);
|
||||
+}
|
||||
+
|
||||
+module_init(myloader_mtd_parser_init);
|
||||
+module_exit(myloader_mtd_parser_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Gabor Juhos <juhosg@openwrt.org>");
|
||||
+MODULE_DESCRIPTION("Parsing code for MyLoader partition tables");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
@@ -0,0 +1,68 @@
|
||||
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
|
||||
@@ -25,6 +25,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)
|
||||
{
|
||||
@@ -79,21 +106,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]);
|
||||
+ part->name = parser_trx_data_part_name(mtd, part->offset);
|
||||
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/parsers/bcm47xxpart.c
|
||||
+++ b/drivers/mtd/parsers/bcm47xxpart.c
|
||||
@@ -35,6 +35,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
|
||||
@@ -178,6 +179,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) {
|
||||
@@ -0,0 +1,38 @@
|
||||
From 4437e01fb6bca63fccdba5d6c44888b0935885c2 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks@slashdirt.org>
|
||||
Date: Tue, 24 Mar 2020 11:45:07 +0100
|
||||
Subject: [PATCH] generic: routerboot partition build bits (5.4)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This patch adds routerbootpart kernel build bits
|
||||
|
||||
Signed-off-by: Thibaut VARÈNE <hacks@slashdirt.org>
|
||||
---
|
||||
drivers/mtd/parsers/Kconfig | 9 +++++++++
|
||||
drivers/mtd/parsers/Makefile | 1 +
|
||||
2 files changed, 10 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/parsers/Kconfig
|
||||
+++ b/drivers/mtd/parsers/Kconfig
|
||||
@@ -195,3 +195,12 @@ config MTD_REDBOOT_PARTS_READONLY
|
||||
'FIS directory' images, enable this option.
|
||||
|
||||
endif # MTD_REDBOOT_PARTS
|
||||
+
|
||||
+config MTD_ROUTERBOOT_PARTS
|
||||
+ tristate "RouterBoot flash partition parser"
|
||||
+ depends on MTD && OF
|
||||
+ help
|
||||
+ MikroTik RouterBoot is implemented as a multi segment system on the
|
||||
+ flash, some of which are fixed and some of which are located at
|
||||
+ variable offsets. This parser handles both cases via properly
|
||||
+ formatted DTS.
|
||||
--- a/drivers/mtd/parsers/Makefile
|
||||
+++ b/drivers/mtd/parsers/Makefile
|
||||
@@ -13,3 +13,4 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
|
||||
obj-$(CONFIG_MTD_PARSER_TRX) += parser_trx.o
|
||||
obj-$(CONFIG_MTD_SHARPSL_PARTS) += sharpslpart.o
|
||||
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
|
||||
+obj-$(CONFIG_MTD_ROUTERBOOT_PARTS) += routerbootpart.o
|
||||
@@ -0,0 +1,25 @@
|
||||
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(-)
|
||||
|
||||
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
|
||||
@@ -913,7 +913,7 @@ static int get_chip(struct map_info *map
|
||||
return 0;
|
||||
|
||||
case FL_ERASING:
|
||||
- if (!cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
|
||||
+ if (1 /* no suspend */ || !cfip || !(cfip->EraseSuspend & (0x1|0x2)) ||
|
||||
!(mode == FL_READY || mode == FL_POINT ||
|
||||
(mode == FL_WRITING && (cfip->EraseSuspend & 0x2))))
|
||||
goto sleep;
|
||||
@@ -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
|
||||
@@ -2057,6 +2057,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,18 @@
|
||||
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(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/macronix.c
|
||||
+++ b/drivers/mtd/spi-nor/macronix.c
|
||||
@@ -93,6 +93,7 @@ static void macronix_default_init(struct
|
||||
{
|
||||
nor->params->quad_enable = spi_nor_sr1_bit6_quad_enable;
|
||||
nor->params->set_4byte_addr_mode = spi_nor_set_4byte_addr_mode;
|
||||
+ nor->flags |= SNOR_F_HAS_LOCK;
|
||||
}
|
||||
|
||||
static const struct spi_nor_fixups macronix_fixups = {
|
||||
@@ -0,0 +1,71 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 4 Nov 2017 07:40:23 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: support limiting 4K sectors support based on
|
||||
flash size
|
||||
|
||||
Some devices need 4K sectors to be able to deal with small flash chips.
|
||||
For instance, w25x05 is 64 KiB in size, and without 4K sectors, the
|
||||
entire chip is just one erase block.
|
||||
On bigger flash chip sizes, using 4K sectors can significantly slow down
|
||||
many operations, including using a writable filesystem. There are several
|
||||
platforms where it makes sense to use a single kernel on both kinds of
|
||||
devices.
|
||||
|
||||
To support this properly, allow configuring an upper flash chip size
|
||||
limit for 4K sectors support.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/mtd/spi-nor/Kconfig
|
||||
+++ b/drivers/mtd/spi-nor/Kconfig
|
||||
@@ -24,6 +24,17 @@ config MTD_SPI_NOR_USE_4K_SECTORS
|
||||
Please note that some tools/drivers/filesystems may not work with
|
||||
4096 B erase size (e.g. UBIFS requires 15 KiB as a minimum).
|
||||
|
||||
+config MTD_SPI_NOR_USE_4K_SECTORS_LIMIT
|
||||
+ int "Maximum flash chip size to use 4K sectors on (in KiB)"
|
||||
+ depends on MTD_SPI_NOR_USE_4K_SECTORS
|
||||
+ default "4096"
|
||||
+ help
|
||||
+ There are many flash chips that support 4K sectors, but are so large
|
||||
+ that using them significantly slows down writing large amounts of
|
||||
+ data or using a writable filesystem.
|
||||
+ Any flash chip larger than the size specified in this option will
|
||||
+ not use 4K sectors.
|
||||
+
|
||||
source "drivers/mtd/spi-nor/controllers/Kconfig"
|
||||
|
||||
endif # MTD_SPI_NOR
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -2786,6 +2786,21 @@ static void spi_nor_info_init_params(str
|
||||
*/
|
||||
erase_mask = 0;
|
||||
i = 0;
|
||||
+#ifdef CONFIG_MTD_SPI_NOR_USE_4K_SECTORS
|
||||
+ if ((info->flags & SECT_4K_PMC) && (params->size <=
|
||||
+ CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) {
|
||||
+ erase_mask |= BIT(i);
|
||||
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
|
||||
+ SPINOR_OP_BE_4K_PMC);
|
||||
+ i++;
|
||||
+ } else if ((info->flags & SECT_4K) && (params->size <=
|
||||
+ CONFIG_MTD_SPI_NOR_USE_4K_SECTORS_LIMIT * 1024)) {
|
||||
+ erase_mask |= BIT(i);
|
||||
+ spi_nor_set_erase_type(&map->erase_type[i], 4096u,
|
||||
+ SPINOR_OP_BE_4K);
|
||||
+ i++;
|
||||
+ }
|
||||
+#else
|
||||
if (info->flags & SECT_4K_PMC) {
|
||||
erase_mask |= BIT(i);
|
||||
spi_nor_set_erase_type(&map->erase_type[i], 4096u,
|
||||
@@ -2797,6 +2812,7 @@ static void spi_nor_info_init_params(str
|
||||
SPINOR_OP_BE_4K);
|
||||
i++;
|
||||
}
|
||||
+#endif
|
||||
erase_mask |= BIT(i);
|
||||
spi_nor_set_erase_type(&map->erase_type[i], info->sector_size,
|
||||
SPINOR_OP_SE);
|
||||
@@ -0,0 +1,18 @@
|
||||
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(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/eon.c
|
||||
+++ b/drivers/mtd/spi-nor/eon.c
|
||||
@@ -15,6 +15,7 @@ static const struct flash_info eon_parts
|
||||
{ "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) },
|
||||
{ "en25q80a", INFO(0x1c3014, 0, 64 * 1024, 16,
|
||||
SECT_4K | SPI_NOR_DUAL_READ) },
|
||||
{ "en25qh16", INFO(0x1c7015, 0, 64 * 1024, 32,
|
||||
@@ -0,0 +1,79 @@
|
||||
From patchwork Thu Feb 6 17:19:41 2020
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
|
||||
X-Patchwork-Id: 1234465
|
||||
Date: Thu, 6 Feb 2020 19:19:41 +0200
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
To: linux-mtd@lists.infradead.org
|
||||
Subject: [PATCH v2] mtd: spi-nor: Add support for xt25f128b chip
|
||||
Message-ID: <20200206171941.GA2398@makrotopia.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Disposition: inline
|
||||
List-Subscribe: <http://lists.infradead.org/mailman/listinfo/linux-mtd>,
|
||||
<mailto:linux-mtd-request@lists.infradead.org?subject=subscribe>
|
||||
Cc: Eitan Cohen <eitan@neot-semadar.com>, Piotr Dymacz <pepe2k@gmail.com>,
|
||||
Tudor Ambarus <tudor.ambarus@microchip.com>
|
||||
Sender: "linux-mtd" <linux-mtd-bounces@lists.infradead.org>
|
||||
Errors-To: linux-mtd-bounces+incoming=patchwork.ozlabs.org@lists.infradead.org
|
||||
|
||||
Add XT25F128B made by XTX Technology (Shenzhen) Limited.
|
||||
This chip supports dual and quad read and uniform 4K-byte erase.
|
||||
Verified on Teltonika RUT955 which comes with XT25F128B in recent
|
||||
versions of the device.
|
||||
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 4 ++++
|
||||
1 file changed, 4 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/Makefile
|
||||
+++ b/drivers/mtd/spi-nor/Makefile
|
||||
@@ -17,6 +17,7 @@ spi-nor-objs += sst.o
|
||||
spi-nor-objs += winbond.o
|
||||
spi-nor-objs += xilinx.o
|
||||
spi-nor-objs += xmc.o
|
||||
+spi-nor-objs += xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor.o
|
||||
|
||||
obj-$(CONFIG_MTD_SPI_NOR) += controllers/
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/spi-nor/xtx.c
|
||||
@@ -0,0 +1,15 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+#include <linux/mtd/spi-nor.h>
|
||||
+
|
||||
+#include "core.h"
|
||||
+
|
||||
+static const struct flash_info xtx_parts[] = {
|
||||
+ /* XTX Technology (Shenzhen) Limited */
|
||||
+ { "xt25f128b", INFO(0x0B4018, 0, 64 * 1024, 256, SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
+};
|
||||
+
|
||||
+const struct spi_nor_manufacturer spi_nor_xtx = {
|
||||
+ .name = "xtx",
|
||||
+ .parts = xtx_parts,
|
||||
+ .nparts = ARRAY_SIZE(xtx_parts),
|
||||
+};
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -2026,6 +2026,7 @@ static const struct spi_nor_manufacturer
|
||||
&spi_nor_winbond,
|
||||
&spi_nor_xilinx,
|
||||
&spi_nor_xmc,
|
||||
+ &spi_nor_xtx,
|
||||
};
|
||||
|
||||
static const struct flash_info *
|
||||
--- a/drivers/mtd/spi-nor/core.h
|
||||
+++ b/drivers/mtd/spi-nor/core.h
|
||||
@@ -398,6 +398,7 @@ extern const struct spi_nor_manufacturer
|
||||
extern const struct spi_nor_manufacturer spi_nor_winbond;
|
||||
extern const struct spi_nor_manufacturer spi_nor_xilinx;
|
||||
extern const struct spi_nor_manufacturer spi_nor_xmc;
|
||||
+extern const struct spi_nor_manufacturer spi_nor_xtx;
|
||||
|
||||
int spi_nor_write_enable(struct spi_nor *nor);
|
||||
int spi_nor_write_disable(struct spi_nor *nor);
|
||||
@@ -0,0 +1,180 @@
|
||||
From ea92cbb50a78404e29de2cc3999a240615ffb1c8 Mon Sep 17 00:00:00 2001
|
||||
From: Chuanhong Guo <gch981213@gmail.com>
|
||||
Date: Mon, 6 Apr 2020 17:58:48 +0800
|
||||
Subject: [PATCH] mtd: spi-nor: rework broken-flash-reset support
|
||||
|
||||
Instead of resetting flash to 3B address on remove hook, this
|
||||
implementation only enters 4B mode when needed, which prevents
|
||||
more unexpected reboot stuck. This implementation makes it only
|
||||
break when a kernel panic happens during flash operation on 16M+
|
||||
areas.
|
||||
*OpenWrt only*: silent broken-flash-reset warning. We are not dealing
|
||||
with vendors and it's unpleasant for users to se that unnecessary
|
||||
and long WARN_ON print.
|
||||
|
||||
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 52 +++++++++++++++++++++++++++++++++--
|
||||
1 file changed, 49 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/core.c
|
||||
+++ b/drivers/mtd/spi-nor/core.c
|
||||
@@ -1447,6 +1447,23 @@ destroy_erase_cmd_list:
|
||||
return ret;
|
||||
}
|
||||
|
||||
+int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr)
|
||||
+{
|
||||
+ u8 addr_width;
|
||||
+
|
||||
+ if ((nor->flags & (SNOR_F_4B_OPCODES | SNOR_F_BROKEN_RESET)) !=
|
||||
+ SNOR_F_BROKEN_RESET)
|
||||
+ return 0;
|
||||
+
|
||||
+ addr_width = addr & 0xff000000 ? 4 : 3;
|
||||
+ if (nor->addr_width == addr_width)
|
||||
+ return 0;
|
||||
+
|
||||
+ nor->addr_width = addr_width;
|
||||
+
|
||||
+ return nor->params->set_4byte_addr_mode(nor, addr_width == 4);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* Erase an address range on the nor chip. The address range may extend
|
||||
* one or more erase sectors. Return an error is there is a problem erasing.
|
||||
@@ -1474,6 +1491,10 @@ static int spi_nor_erase(struct mtd_info
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = spi_nor_check_set_addr_width(nor, instr->addr + instr->len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
/* whole-chip erase? */
|
||||
if (len == mtd->size && !(nor->flags & SNOR_F_NO_OP_CHIP_ERASE)) {
|
||||
unsigned long timeout;
|
||||
@@ -1533,6 +1554,7 @@ static int spi_nor_erase(struct mtd_info
|
||||
ret = spi_nor_write_disable(nor);
|
||||
|
||||
erase_err:
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
|
||||
return ret;
|
||||
@@ -1872,7 +1894,9 @@ static int spi_nor_lock(struct mtd_info
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ spi_nor_check_set_addr_width(nor, ofs + len);
|
||||
ret = nor->params->locking_ops->lock(nor, ofs, len);
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
@@ -1887,7 +1911,9 @@ static int spi_nor_unlock(struct mtd_inf
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ spi_nor_check_set_addr_width(nor, ofs + len);
|
||||
ret = nor->params->locking_ops->unlock(nor, ofs, len);
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
@@ -1902,7 +1928,9 @@ static int spi_nor_is_locked(struct mtd_
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ spi_nor_check_set_addr_width(nor, ofs + len);
|
||||
ret = nor->params->locking_ops->is_locked(nor, ofs, len);
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
@@ -2095,6 +2123,10 @@ static int spi_nor_read(struct mtd_info
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = spi_nor_check_set_addr_width(nor, from + len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
while (len) {
|
||||
loff_t addr = from;
|
||||
|
||||
@@ -2118,6 +2150,7 @@ static int spi_nor_read(struct mtd_info
|
||||
ret = 0;
|
||||
|
||||
read_err:
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
@@ -2140,6 +2173,10 @@ static int spi_nor_write(struct mtd_info
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = spi_nor_check_set_addr_width(nor, to + len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
for (i = 0; i < len; ) {
|
||||
ssize_t written;
|
||||
loff_t addr = to + i;
|
||||
@@ -2182,6 +2219,7 @@ static int spi_nor_write(struct mtd_info
|
||||
}
|
||||
|
||||
write_err:
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
@@ -2977,9 +3015,13 @@ static int spi_nor_init(struct spi_nor *
|
||||
* reboots (e.g., crashes). Warn the user (or hopefully, system
|
||||
* designer) that this is bad.
|
||||
*/
|
||||
- WARN_ONCE(nor->flags & SNOR_F_BROKEN_RESET,
|
||||
- "enabling reset hack; may not recover from unexpected reboots\n");
|
||||
- nor->params->set_4byte_addr_mode(nor, true);
|
||||
+ if (nor->flags & SNOR_F_BROKEN_RESET) {
|
||||
+ dev_warn(nor->dev,
|
||||
+ "enabling reset hack; may not recover from unexpected reboots\n");
|
||||
+ nor->addr_width = 3;
|
||||
+ } else {
|
||||
+ nor->params->set_4byte_addr_mode(nor, true);
|
||||
+ }
|
||||
}
|
||||
|
||||
return 0;
|
||||
--- a/drivers/mtd/spi-nor/core.h
|
||||
+++ b/drivers/mtd/spi-nor/core.h
|
||||
@@ -400,6 +400,7 @@ extern const struct spi_nor_manufacturer
|
||||
extern const struct spi_nor_manufacturer spi_nor_xmc;
|
||||
extern const struct spi_nor_manufacturer spi_nor_xtx;
|
||||
|
||||
+int spi_nor_check_set_addr_width(struct spi_nor *nor, loff_t addr);
|
||||
int spi_nor_write_enable(struct spi_nor *nor);
|
||||
int spi_nor_write_disable(struct spi_nor *nor);
|
||||
int spi_nor_set_4byte_addr_mode(struct spi_nor *nor, bool enable);
|
||||
--- a/drivers/mtd/spi-nor/sst.c
|
||||
+++ b/drivers/mtd/spi-nor/sst.c
|
||||
@@ -55,6 +55,10 @@ static int sst_write(struct mtd_info *mt
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ ret = spi_nor_check_set_addr_width(nor, to + len);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
ret = spi_nor_write_enable(nor);
|
||||
if (ret)
|
||||
goto out;
|
||||
@@ -124,6 +128,7 @@ static int sst_write(struct mtd_info *mt
|
||||
}
|
||||
out:
|
||||
*retlen += actual;
|
||||
+ spi_nor_check_set_addr_width(nor, 0);
|
||||
spi_nor_unlock_and_unprep(nor);
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
From d68b4aa22e8c625685bfad642dd7337948dc0ad1 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
Date: Mon, 6 Jan 2020 13:07:56 +0100
|
||||
Subject: [PATCH] mtd: spi-nor: add support for Gigadevice GD25D05
|
||||
|
||||
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 5 +++++
|
||||
1 file changed, 5 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/gigadevice.c
|
||||
+++ b/drivers/mtd/spi-nor/gigadevice.c
|
||||
@@ -24,6 +24,9 @@ static struct spi_nor_fixups gd25q256_fi
|
||||
};
|
||||
|
||||
static const struct flash_info gigadevice_parts[] = {
|
||||
+ { "gd25q05", INFO(0xc84010, 0, 64 * 1024, 1,
|
||||
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
|
||||
{ "gd25q16", INFO(0xc84015, 0, 64 * 1024, 32,
|
||||
SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB) },
|
||||
@@ -0,0 +1,12 @@
|
||||
--- a/drivers/mtd/spi-nor/gigadevice.c
|
||||
+++ b/drivers/mtd/spi-nor/gigadevice.c
|
||||
@@ -53,6 +53,9 @@ static const struct flash_info gigadevic
|
||||
SPI_NOR_4B_OPCODES | SPI_NOR_HAS_LOCK |
|
||||
SPI_NOR_HAS_TB | SPI_NOR_TB_SR_BIT6)
|
||||
.fixups = &gd25q256_fixups },
|
||||
+ { "gd25q512", INFO(0xc84020, 0, 64 * 1024, 1024,
|
||||
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ |
|
||||
+ SPI_NOR_HAS_LOCK | SPI_NOR_HAS_TB | SPI_NOR_4B_OPCODES) },
|
||||
};
|
||||
|
||||
const struct spi_nor_manufacturer spi_nor_gigadevice = {
|
||||
@@ -0,0 +1,178 @@
|
||||
From a07e31adf2753cad2fd9790db5bfc047c81e8152 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Matouschek <felix@matouschek.org>
|
||||
Date: Fri, 2 Jul 2021 20:31:23 +0200
|
||||
Subject: [PATCH] mtd: spinand: Add support for XTX XT26G0xA
|
||||
|
||||
Add support for XTX Technology XT26G01AXXXXX, XTX26G02AXXXXX and
|
||||
XTX26G04AXXXXX SPI NAND.
|
||||
|
||||
These are 3V, 1G/2G/4Gbit serial SLC NAND flash devices with on-die ECC
|
||||
(8bit strength per 512bytes).
|
||||
|
||||
Tested on Teltonika RUTX10 flashed with OpenWrt.
|
||||
|
||||
Datasheets available at
|
||||
http://www.xtxtech.com/download/?AId=225
|
||||
https://datasheet.lcsc.com/szlcsc/2005251034_XTX-XT26G01AWSEGA_C558841.pdf
|
||||
|
||||
Signed-off-by: Felix Matouschek <felix@matouschek.org>
|
||||
---
|
||||
drivers/mtd/nand/spi/Makefile | 2 +-
|
||||
drivers/mtd/nand/spi/core.c | 1 +
|
||||
drivers/mtd/nand/spi/xtx.c | 122 ++++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/spinand.h | 1 +
|
||||
4 files changed, 125 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/mtd/nand/spi/xtx.c
|
||||
|
||||
--- a/drivers/mtd/nand/spi/Makefile
|
||||
+++ b/drivers/mtd/nand/spi/Makefile
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
-spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
|
||||
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o xtx.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -760,6 +760,7 @@ static const struct spinand_manufacturer
|
||||
¶gon_spinand_manufacturer,
|
||||
&toshiba_spinand_manufacturer,
|
||||
&winbond_spinand_manufacturer,
|
||||
+ &xtx_spinand_manufacturer,
|
||||
};
|
||||
|
||||
static int spinand_manufacturer_match(struct spinand_device *spinand,
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/spi/xtx.c
|
||||
@@ -0,0 +1,122 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Author:
|
||||
+ * Felix Matouschek <felix@matouschek.org>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mtd/spinand.h>
|
||||
+
|
||||
+#define SPINAND_MFR_XTX 0x0B
|
||||
+
|
||||
+#define XT26G0XA_STATUS_ECC_MASK GENMASK(5, 2)
|
||||
+#define XT26G0XA_STATUS_ECC_NO_DETECTED (0 << 2)
|
||||
+#define XT26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
|
||||
+#define XT26G0XA_STATUS_ECC_UNCOR_ERROR (2 << 4)
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
+
|
||||
+static int xt26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = 8;
|
||||
+ region->length = 40;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int xt26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = 1;
|
||||
+ region->length = 7;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct mtd_ooblayout_ops xt26g0xa_ooblayout = {
|
||||
+ .ecc = xt26g0xa_ooblayout_ecc,
|
||||
+ .free = xt26g0xa_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
+static int xt26g0xa_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ switch (status & XT26G0XA_STATUS_ECC_MASK) {
|
||||
+ case XT26G0XA_STATUS_ECC_NO_DETECTED:
|
||||
+ return 0;
|
||||
+ case XT26G0XA_STATUS_ECC_8_CORRECTED:
|
||||
+ return 8;
|
||||
+ case XT26G0XA_STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+ default: /* (1 << 2) through (7 << 2) are 1-7 corrected errors */
|
||||
+ return (status & XT26G0XA_STATUS_ECC_MASK) >> 2;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static const struct spinand_info xtx_spinand_table[] = {
|
||||
+ SPINAND_INFO("XT26G01A",
|
||||
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE1),
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 20, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ SPINAND_HAS_QE_BIT,
|
||||
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
|
||||
+ xt26g0xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("XT26G02A",
|
||||
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE2),
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 40, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ SPINAND_HAS_QE_BIT,
|
||||
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
|
||||
+ xt26g0xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("XT26G04A",
|
||||
+ SPINAND_ID(SPINAND_READID_METHOD_OPCODE_DUMMY, 0xE3),
|
||||
+ NAND_MEMORG(1, 2048, 64, 128, 2048, 40, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ SPINAND_HAS_QE_BIT,
|
||||
+ SPINAND_ECCINFO(&xt26g0xa_ooblayout,
|
||||
+ xt26g0xa_ecc_get_status)),
|
||||
+};
|
||||
+
|
||||
+static const struct spinand_manufacturer_ops xtx_spinand_manuf_ops = {
|
||||
+};
|
||||
+
|
||||
+const struct spinand_manufacturer xtx_spinand_manufacturer = {
|
||||
+ .id = SPINAND_MFR_XTX,
|
||||
+ .name = "XTX",
|
||||
+ .chips = xtx_spinand_table,
|
||||
+ .nchips = ARRAY_SIZE(xtx_spinand_table),
|
||||
+ .ops = &xtx_spinand_manuf_ops,
|
||||
+};
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -244,6 +244,7 @@ extern const struct spinand_manufacturer
|
||||
extern const struct spinand_manufacturer paragon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
+extern const struct spinand_manufacturer xtx_spinand_manufacturer;
|
||||
|
||||
/**
|
||||
* struct spinand_op_variants - SPI NAND operation variants
|
||||
@@ -0,0 +1,97 @@
|
||||
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
|
||||
@@ -1192,6 +1192,73 @@ 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;
|
||||
+ loff_t offset = 0;
|
||||
+ size_t len;
|
||||
+ char magic[4];
|
||||
+
|
||||
+ /* 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))
|
||||
+ return;
|
||||
+
|
||||
+ /* get the first not bad block */
|
||||
+ if (mtd_can_have_bb(mtd))
|
||||
+ while (mtd_block_isbad(mtd, offset)) {
|
||||
+ offset += mtd->erasesize;
|
||||
+
|
||||
+ if (offset > mtd->size) {
|
||||
+ pr_err("UBI error: Failed to find a non-bad "
|
||||
+ "block on mtd%d\n", mtd->index);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* check if the read from flash was successful */
|
||||
+ err = mtd_read(mtd, offset, 4, &len, (void *) magic);
|
||||
+ if ((err && !mtd_is_bitflip(err)) || len != 4) {
|
||||
+ pr_err("UBI error: unable to read from mtd%d\n", mtd->index);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* check for a valid ubi magic */
|
||||
+ if (strncmp(magic, "UBI#", 4)) {
|
||||
+ pr_err("UBI error: no valid UBI magic found inside mtd%d\n", mtd->index);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ /* don't auto-add media types where UBI doesn't makes sense */
|
||||
+ if (mtd->type != MTD_NANDFLASH &&
|
||||
+ mtd->type != MTD_NORFLASH &&
|
||||
+ mtd->type != MTD_DATAFLASH &&
|
||||
+ mtd->type != MTD_MLCNANDFLASH)
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ 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\n", mtd->index);
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ return;
|
||||
+
|
||||
+cleanup:
|
||||
+ put_mtd_device(mtd);
|
||||
+}
|
||||
+
|
||||
static int __init ubi_init(void)
|
||||
{
|
||||
int err, i, k;
|
||||
@@ -1275,6 +1342,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\n", err);
|
||||
@@ -0,0 +1,69 @@
|
||||
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
|
||||
@@ -652,6 +652,47 @@ 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))
|
||||
+ desc = ubi_open_volume_nm(ubi_num, "fit", 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;
|
||||
@@ -684,6 +725,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
|
||||
@@ -474,7 +474,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
|
||||
@@ -567,6 +588,10 @@ void __init mount_root(void)
|
||||
return;
|
||||
}
|
||||
#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
|
||||
@@ -42,6 +42,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"
|
||||
@@ -458,6 +459,15 @@ int ubiblock_create(struct ubi_volume_in
|
||||
dev_info(disk_to_dev(dev->gd), "created from ubi%d:%d(%s)",
|
||||
dev->ubi_num, dev->vol_id, vi->name);
|
||||
mutex_unlock(&devices_mutex);
|
||||
+
|
||||
+ 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,60 @@
|
||||
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(-)
|
||||
|
||||
--- a/drivers/mtd/ubi/attach.c
|
||||
+++ b/drivers/mtd/ubi/attach.c
|
||||
@@ -926,6 +926,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
|
||||
@@ -958,9 +965,21 @@ static int scan_peb(struct ubi_device *u
|
||||
return 0;
|
||||
}
|
||||
|
||||
- err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
|
||||
- if (err < 0)
|
||||
- return err;
|
||||
+ if (!ai->eof_found) {
|
||||
+ err = ubi_io_read_ec_hdr(ubi, pnum, ech, 0);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ if (ec_hdr_has_eof(ech)) {
|
||||
+ pr_notice("UBI: EOF marker found, PEBs from %d will be erased\n",
|
||||
+ pnum);
|
||||
+ ai->eof_found = true;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (ai->eof_found)
|
||||
+ err = UBI_IO_FF_BITFLIPS;
|
||||
+
|
||||
switch (err) {
|
||||
case 0:
|
||||
break;
|
||||
--- a/drivers/mtd/ubi/ubi.h
|
||||
+++ b/drivers/mtd/ubi/ubi.h
|
||||
@@ -782,6 +782,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;
|
||||
@@ -0,0 +1,75 @@
|
||||
From 1bd1b740f208d1cf4071932cc51860d37266c402 Mon Sep 17 00:00:00 2001
|
||||
From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
Date: Sat, 1 Sep 2018 00:30:11 +0200
|
||||
Subject: [PATCH 495/497] mtd: core: add get_mtd_device_by_node
|
||||
|
||||
Add function to retrieve a mtd device by its OF node. Since drivers can
|
||||
assign arbitrary names to mtd devices in the absence of a label
|
||||
property, there is no other reliable way to retrieve a mtd device for a
|
||||
given OF node.
|
||||
|
||||
Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
Reviewed-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/mtdcore.c | 38 ++++++++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/mtd.h | 2 ++
|
||||
2 files changed, 40 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -1046,6 +1046,44 @@ out_unlock:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(get_mtd_device_nm);
|
||||
|
||||
+/**
|
||||
+ * get_mtd_device_by_node - obtain a validated handle for an MTD device
|
||||
+ * by of_node
|
||||
+ * @of_node: OF node of MTD device to open
|
||||
+ *
|
||||
+ * This function returns MTD device description structure in case of
|
||||
+ * success and an error code in case of failure.
|
||||
+ */
|
||||
+struct mtd_info *get_mtd_device_by_node(const struct device_node *of_node)
|
||||
+{
|
||||
+ int err = -ENODEV;
|
||||
+ struct mtd_info *mtd = NULL, *other;
|
||||
+
|
||||
+ mutex_lock(&mtd_table_mutex);
|
||||
+
|
||||
+ mtd_for_each_device(other) {
|
||||
+ if (of_node == other->dev.of_node) {
|
||||
+ mtd = other;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!mtd)
|
||||
+ goto out_unlock;
|
||||
+
|
||||
+ err = __get_mtd_device(mtd);
|
||||
+ if (err)
|
||||
+ goto out_unlock;
|
||||
+
|
||||
+ mutex_unlock(&mtd_table_mutex);
|
||||
+ return mtd;
|
||||
+
|
||||
+out_unlock:
|
||||
+ mutex_unlock(&mtd_table_mutex);
|
||||
+ return ERR_PTR(err);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(get_mtd_device_by_node);
|
||||
+
|
||||
void put_mtd_device(struct mtd_info *mtd)
|
||||
{
|
||||
mutex_lock(&mtd_table_mutex);
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -696,6 +696,8 @@ extern struct mtd_info *get_mtd_device(s
|
||||
extern int __get_mtd_device(struct mtd_info *mtd);
|
||||
extern void __put_mtd_device(struct mtd_info *mtd);
|
||||
extern struct mtd_info *get_mtd_device_nm(const char *name);
|
||||
+extern struct mtd_info *get_mtd_device_by_node(
|
||||
+ const struct device_node *of_node);
|
||||
extern void put_mtd_device(struct mtd_info *mtd);
|
||||
|
||||
static inline uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
|
||||
@@ -0,0 +1,52 @@
|
||||
From 5734c6669fba7ddb5ef491ccff7159d15dba0b59 Mon Sep 17 00:00:00 2001
|
||||
From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
Date: Wed, 5 Sep 2018 01:32:51 +0200
|
||||
Subject: [PATCH 496/497] dt-bindings: add bindings for mtd-concat devices
|
||||
|
||||
Document virtual mtd-concat device bindings.
|
||||
|
||||
Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
---
|
||||
.../devicetree/bindings/mtd/mtd-concat.txt | 36 +++++++++++++++++++
|
||||
1 file changed, 36 insertions(+)
|
||||
create mode 100644 Documentation/devicetree/bindings/mtd/mtd-concat.txt
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/devicetree/bindings/mtd/mtd-concat.txt
|
||||
@@ -0,0 +1,36 @@
|
||||
+Virtual MTD concat device
|
||||
+
|
||||
+Requires properties:
|
||||
+- devices: list of phandles to mtd nodes that should be concatenated
|
||||
+
|
||||
+Example:
|
||||
+
|
||||
+&spi {
|
||||
+ flash0: flash@0 {
|
||||
+ ...
|
||||
+ };
|
||||
+ flash1: flash@1 {
|
||||
+ ...
|
||||
+ };
|
||||
+};
|
||||
+
|
||||
+flash {
|
||||
+ compatible = "mtd-concat";
|
||||
+
|
||||
+ devices = <&flash0 &flash1>;
|
||||
+
|
||||
+ partitions {
|
||||
+ compatible = "fixed-partitions";
|
||||
+
|
||||
+ partition@0 {
|
||||
+ label = "boot";
|
||||
+ reg = <0x0000000 0x0040000>;
|
||||
+ read-only;
|
||||
+ };
|
||||
+
|
||||
+ partition@40000 {
|
||||
+ label = "firmware";
|
||||
+ reg = <0x0040000 0x1fc0000>;
|
||||
+ };
|
||||
+ }
|
||||
+}
|
||||
@@ -0,0 +1,216 @@
|
||||
From e53f712d8eac71f54399b61038ccf87d2cee99d7 Mon Sep 17 00:00:00 2001
|
||||
From: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
Date: Sat, 25 Aug 2018 12:35:22 +0200
|
||||
Subject: [PATCH 497/497] mtd: mtdconcat: add dt driver for concat devices
|
||||
|
||||
Some mtd drivers like physmap variants have support for concatenating
|
||||
multiple mtd devices, but there is no generic way to define such a
|
||||
concat device from within the device tree.
|
||||
|
||||
This is useful for some SoC boards that use multiple flash chips as
|
||||
memory banks of a single mtd device, with partitions spanning chip
|
||||
borders.
|
||||
|
||||
This commit adds a driver for creating virtual mtd-concat devices. They
|
||||
must have a compatible = "mtd-concat" line, and define a list of devices
|
||||
to concat in the 'devices' property, for example:
|
||||
|
||||
flash {
|
||||
compatible = "mtd-concat";
|
||||
|
||||
devices = <&flash0 &flash1>;
|
||||
|
||||
partitions {
|
||||
...
|
||||
};
|
||||
};
|
||||
|
||||
The driver is added to the very end of the mtd Makefile to increase the
|
||||
likelyhood of all child devices already being loaded at the time of
|
||||
probing, preventing unnecessary deferred probes.
|
||||
|
||||
Signed-off-by: Bernhard Frauendienst <kernel@nospam.obeliks.de>
|
||||
---
|
||||
drivers/mtd/Kconfig | 2 +
|
||||
drivers/mtd/Makefile | 3 +
|
||||
drivers/mtd/composite/Kconfig | 12 +++
|
||||
drivers/mtd/composite/Makefile | 6 ++
|
||||
drivers/mtd/composite/virt_concat.c | 128 ++++++++++++++++++++++++++++
|
||||
5 files changed, 151 insertions(+)
|
||||
create mode 100644 drivers/mtd/composite/Kconfig
|
||||
create mode 100644 drivers/mtd/composite/Makefile
|
||||
create mode 100644 drivers/mtd/composite/virt_concat.c
|
||||
|
||||
--- a/drivers/mtd/Kconfig
|
||||
+++ b/drivers/mtd/Kconfig
|
||||
@@ -238,4 +238,6 @@ source "drivers/mtd/ubi/Kconfig"
|
||||
|
||||
source "drivers/mtd/hyperbus/Kconfig"
|
||||
|
||||
+source "drivers/mtd/composite/Kconfig"
|
||||
+
|
||||
endif # MTD
|
||||
--- a/drivers/mtd/Makefile
|
||||
+++ b/drivers/mtd/Makefile
|
||||
@@ -33,3 +33,6 @@ obj-y += chips/ lpddr/ maps/ devices/ n
|
||||
obj-$(CONFIG_MTD_SPI_NOR) += spi-nor/
|
||||
obj-$(CONFIG_MTD_UBI) += ubi/
|
||||
obj-$(CONFIG_MTD_HYPERBUS) += hyperbus/
|
||||
+
|
||||
+# Composite drivers must be loaded last
|
||||
+obj-y += composite/
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/composite/Kconfig
|
||||
@@ -0,0 +1,12 @@
|
||||
+menu "Composite MTD device drivers"
|
||||
+ depends on MTD!=n
|
||||
+
|
||||
+config MTD_VIRT_CONCAT
|
||||
+ tristate "Virtual concat MTD device"
|
||||
+ help
|
||||
+ This driver allows creation of a virtual MTD concat device, which
|
||||
+ concatenates multiple underlying MTD devices to a single device.
|
||||
+ This is required by some SoC boards where multiple memory banks are
|
||||
+ used as one device with partitions spanning across device boundaries.
|
||||
+
|
||||
+endmenu
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/composite/Makefile
|
||||
@@ -0,0 +1,6 @@
|
||||
+# SPDX-License-Identifier: GPL-2.0
|
||||
+#
|
||||
+# linux/drivers/mtd/composite/Makefile
|
||||
+#
|
||||
+
|
||||
+obj-$(CONFIG_MTD_VIRT_CONCAT) += virt_concat.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/composite/virt_concat.c
|
||||
@@ -0,0 +1,128 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/*
|
||||
+ * Virtual concat MTD device driver
|
||||
+ *
|
||||
+ * Copyright (C) 2018 Bernhard Frauendienst
|
||||
+ * Author: Bernhard Frauendienst, kernel@nospam.obeliks.de
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/mtd/concat.h>
|
||||
+#include <linux/mtd/mtd.h>
|
||||
+#include <linux/mtd/partitions.h>
|
||||
+#include <linux/of.h>
|
||||
+#include <linux/of_platform.h>
|
||||
+#include <linux/slab.h>
|
||||
+
|
||||
+/*
|
||||
+ * struct of_virt_concat - platform device driver data.
|
||||
+ * @cmtd the final mtd_concat device
|
||||
+ * @num_devices the number of devices in @devices
|
||||
+ * @devices points to an array of devices already loaded
|
||||
+ */
|
||||
+struct of_virt_concat {
|
||||
+ struct mtd_info *cmtd;
|
||||
+ int num_devices;
|
||||
+ struct mtd_info **devices;
|
||||
+};
|
||||
+
|
||||
+static int virt_concat_remove(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct of_virt_concat *info;
|
||||
+ int i;
|
||||
+
|
||||
+ info = platform_get_drvdata(pdev);
|
||||
+ if (!info)
|
||||
+ return 0;
|
||||
+
|
||||
+ // unset data for when this is called after a probe error
|
||||
+ platform_set_drvdata(pdev, NULL);
|
||||
+
|
||||
+ if (info->cmtd) {
|
||||
+ mtd_device_unregister(info->cmtd);
|
||||
+ mtd_concat_destroy(info->cmtd);
|
||||
+ }
|
||||
+
|
||||
+ if (info->devices) {
|
||||
+ for (i = 0; i < info->num_devices; i++)
|
||||
+ put_mtd_device(info->devices[i]);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int virt_concat_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device_node *node = pdev->dev.of_node;
|
||||
+ struct of_phandle_iterator it;
|
||||
+ struct of_virt_concat *info;
|
||||
+ struct mtd_info *mtd;
|
||||
+ int err = 0, count;
|
||||
+
|
||||
+ count = of_count_phandle_with_args(node, "devices", NULL);
|
||||
+ if (count <= 0)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
|
||||
+ if (!info)
|
||||
+ return -ENOMEM;
|
||||
+ info->devices = devm_kcalloc(&pdev->dev, count,
|
||||
+ sizeof(*(info->devices)), GFP_KERNEL);
|
||||
+ if (!info->devices) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto err_remove;
|
||||
+ }
|
||||
+
|
||||
+ platform_set_drvdata(pdev, info);
|
||||
+
|
||||
+ of_for_each_phandle(&it, err, node, "devices", NULL, 0) {
|
||||
+ mtd = get_mtd_device_by_node(it.node);
|
||||
+ if (IS_ERR(mtd)) {
|
||||
+ of_node_put(it.node);
|
||||
+ err = -EPROBE_DEFER;
|
||||
+ goto err_remove;
|
||||
+ }
|
||||
+
|
||||
+ info->devices[info->num_devices++] = mtd;
|
||||
+ }
|
||||
+
|
||||
+ info->cmtd = mtd_concat_create(info->devices, info->num_devices,
|
||||
+ dev_name(&pdev->dev));
|
||||
+ if (!info->cmtd) {
|
||||
+ err = -ENXIO;
|
||||
+ goto err_remove;
|
||||
+ }
|
||||
+
|
||||
+ info->cmtd->dev.parent = &pdev->dev;
|
||||
+ mtd_set_of_node(info->cmtd, node);
|
||||
+ mtd_device_register(info->cmtd, NULL, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+
|
||||
+err_remove:
|
||||
+ virt_concat_remove(pdev);
|
||||
+
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static const struct of_device_id virt_concat_of_match[] = {
|
||||
+ { .compatible = "mtd-concat", },
|
||||
+ { /* sentinel */ }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, virt_concat_of_match);
|
||||
+
|
||||
+static struct platform_driver virt_concat_driver = {
|
||||
+ .probe = virt_concat_probe,
|
||||
+ .remove = virt_concat_remove,
|
||||
+ .driver = {
|
||||
+ .name = "virt-mtdconcat",
|
||||
+ .of_match_table = virt_concat_of_match,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+module_platform_driver(virt_concat_driver);
|
||||
+
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
+MODULE_AUTHOR("Bernhard Frauendienst <kernel@nospam.obeliks.de>");
|
||||
+MODULE_DESCRIPTION("Virtual concat MTD device driver");
|
||||
@@ -0,0 +1,40 @@
|
||||
--- a/fs/hfs/Kconfig
|
||||
+++ b/fs/hfs/Kconfig
|
||||
@@ -2,6 +2,7 @@
|
||||
config HFS_FS
|
||||
tristate "Apple Macintosh file system support"
|
||||
depends on BLOCK
|
||||
+ select CDROM
|
||||
select NLS
|
||||
help
|
||||
If you say Y here, you will be able to mount Macintosh-formatted
|
||||
--- a/fs/hfsplus/Kconfig
|
||||
+++ b/fs/hfsplus/Kconfig
|
||||
@@ -2,6 +2,7 @@
|
||||
config HFSPLUS_FS
|
||||
tristate "Apple Extended HFS file system support"
|
||||
depends on BLOCK
|
||||
+ select CDROM
|
||||
select NLS
|
||||
select NLS_UTF8
|
||||
help
|
||||
--- a/fs/isofs/Kconfig
|
||||
+++ b/fs/isofs/Kconfig
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config ISO9660_FS
|
||||
tristate "ISO 9660 CDROM file system support"
|
||||
+ select CDROM
|
||||
help
|
||||
This is the standard file system used on CD-ROMs. It was previously
|
||||
known as "High Sierra File System" and is called "hsfs" on other
|
||||
--- a/fs/udf/Kconfig
|
||||
+++ b/fs/udf/Kconfig
|
||||
@@ -1,6 +1,7 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config UDF_FS
|
||||
tristate "UDF file system support"
|
||||
+ select CDROM
|
||||
select CRC_ITU_T
|
||||
select NLS
|
||||
help
|
||||
File diff suppressed because it is too large
Load Diff
65
target/linux/generic/pending-5.10/532-jffs2_eofdetect.patch
Normal file
65
target/linux/generic/pending-5.10/532-jffs2_eofdetect.patch
Normal file
@@ -0,0 +1,65 @@
|
||||
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(-)
|
||||
|
||||
--- a/fs/jffs2/build.c
|
||||
+++ b/fs/jffs2/build.c
|
||||
@@ -117,6 +117,16 @@ static int jffs2_build_filesystem(struct
|
||||
dbg_fsbuild("scanned flash completely\n");
|
||||
jffs2_dbg_dump_block_lists_nolock(c);
|
||||
|
||||
+ if (c->flags & (1 << 7)) {
|
||||
+ printk("%s(): unlocking the mtd device... ", __func__);
|
||||
+ mtd_unlock(c->mtd, 0, c->mtd->size);
|
||||
+ printk("done.\n");
|
||||
+
|
||||
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
|
||||
+ jffs2_erase_pending_blocks(c, -1);
|
||||
+ printk("done.\n");
|
||||
+ }
|
||||
+
|
||||
dbg_fsbuild("pass 1 starting\n");
|
||||
c->flags |= JFFS2_SB_FLAG_BUILDING;
|
||||
/* Now scan the directory tree, increasing nlink according to every dirent found. */
|
||||
--- a/fs/jffs2/scan.c
|
||||
+++ b/fs/jffs2/scan.c
|
||||
@@ -148,8 +148,14 @@ int jffs2_scan_medium(struct jffs2_sb_in
|
||||
/* reset summary info for next eraseblock scan */
|
||||
jffs2_sum_reset_collected(s);
|
||||
|
||||
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
|
||||
- buf_size, s);
|
||||
+ if (c->flags & (1 << 7)) {
|
||||
+ if (mtd_block_isbad(c->mtd, jeb->offset))
|
||||
+ ret = BLK_STATE_BADBLOCK;
|
||||
+ else
|
||||
+ ret = BLK_STATE_ALLFF;
|
||||
+ } else
|
||||
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
|
||||
+ buf_size, s);
|
||||
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
@@ -565,6 +571,17 @@ full_scan:
|
||||
return err;
|
||||
}
|
||||
|
||||
+ if ((buf[0] == 0xde) &&
|
||||
+ (buf[1] == 0xad) &&
|
||||
+ (buf[2] == 0xc0) &&
|
||||
+ (buf[3] == 0xde)) {
|
||||
+ /* end of filesystem. erase everything after this point */
|
||||
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
|
||||
+ c->flags |= (1 << 7);
|
||||
+
|
||||
+ return BLK_STATE_ALLFF;
|
||||
+ }
|
||||
+
|
||||
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
|
||||
ofs = 0;
|
||||
max_ofs = EMPTY_SCAN_SIZE(c->sector_size);
|
||||
@@ -0,0 +1,88 @@
|
||||
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(-)
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_standalone.c
|
||||
+++ b/net/netfilter/nf_conntrack_standalone.c
|
||||
@@ -9,6 +9,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>
|
||||
@@ -457,6 +458,56 @@ static int ct_cpu_seq_show(struct seq_fi
|
||||
return 0;
|
||||
}
|
||||
|
||||
+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 int ct_file_write(struct file *file, char *buf, size_t count)
|
||||
+{
|
||||
+ struct seq_file *seq = file->private_data;
|
||||
+ struct net *net = seq_file_net(seq);
|
||||
+ struct kill_request kr = { };
|
||||
+
|
||||
+ if (count == 0)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (count >= INET6_ADDRSTRLEN)
|
||||
+ count = INET6_ADDRSTRLEN - 1;
|
||||
+
|
||||
+ if (strnchr(buf, count, ':')) {
|
||||
+ kr.family = AF_INET6;
|
||||
+ if (!in6_pton(buf, count, (void *)&kr.addr, '\n', NULL))
|
||||
+ return -EINVAL;
|
||||
+ } else if (strnchr(buf, count, '.')) {
|
||||
+ kr.family = AF_INET;
|
||||
+ if (!in4_pton(buf, count, (void *)&kr.addr, '\n', NULL))
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ nf_ct_iterate_cleanup_net(net, kill_matching, &kr, 0, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static const struct seq_operations ct_cpu_seq_ops = {
|
||||
.start = ct_cpu_seq_start,
|
||||
.next = ct_cpu_seq_next,
|
||||
@@ -470,8 +521,9 @@ static int nf_conntrack_standalone_init_
|
||||
kuid_t root_uid;
|
||||
kgid_t root_gid;
|
||||
|
||||
- pde = proc_create_net("nf_conntrack", 0440, net->proc_net, &ct_seq_ops,
|
||||
- sizeof(struct ct_iter_state));
|
||||
+ pde = proc_create_net_data_write("nf_conntrack", 0440, net->proc_net,
|
||||
+ &ct_seq_ops, &ct_file_write,
|
||||
+ sizeof(struct ct_iter_state), NULL);
|
||||
if (!pde)
|
||||
goto out_nf_conntrack;
|
||||
|
||||
@@ -0,0 +1,110 @@
|
||||
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(+)
|
||||
|
||||
--- a/include/uapi/linux/netfilter_ipv4/ip_tables.h
|
||||
+++ b/include/uapi/linux/netfilter_ipv4/ip_tables.h
|
||||
@@ -89,6 +89,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. */
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -50,6 +50,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,
|
||||
@@ -80,6 +83,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)
|
||||
{
|
||||
@@ -524,6 +550,8 @@ find_check_entry(struct ipt_entry *e, st
|
||||
struct xt_mtchk_param mtpar;
|
||||
struct xt_entry_match *ematch;
|
||||
|
||||
+ ip_checkdefault(&e->ip);
|
||||
+
|
||||
if (!xt_percpu_counter_alloc(alloc_state, &e->counters))
|
||||
return -ENOMEM;
|
||||
|
||||
@@ -818,6 +846,7 @@ copy_entries_to_user(unsigned int total_
|
||||
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))
|
||||
@@ -845,6 +874,14 @@ copy_entries_to_user(unsigned int total_
|
||||
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) {
|
||||
@@ -1223,12 +1260,15 @@ compat_copy_entry_to_user(struct ipt_ent
|
||||
compat_uint_t origsize;
|
||||
const struct xt_entry_match *ematch;
|
||||
int ret = 0;
|
||||
+ u8 flags = e->ip.flags & IPT_F_MASK;
|
||||
|
||||
origsize = *size;
|
||||
ce = *dstptr;
|
||||
if (copy_to_user(ce, e, sizeof(struct ipt_entry)) != 0 ||
|
||||
copy_to_user(&ce->counters, &counters[i],
|
||||
- sizeof(counters[i])) != 0)
|
||||
+ sizeof(counters[i])) != 0 ||
|
||||
+ copy_to_user(&ce->ip.flags, &flags,
|
||||
+ sizeof(flags)) != 0)
|
||||
return -EFAULT;
|
||||
|
||||
*dstptr += sizeof(struct compat_ipt_entry);
|
||||
@@ -0,0 +1,106 @@
|
||||
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(-)
|
||||
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -246,6 +246,33 @@ struct ipt_entry *ipt_next_entry(const s
|
||||
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,
|
||||
@@ -266,27 +293,28 @@ ipt_do_table(struct sk_buff *skb,
|
||||
unsigned int addend;
|
||||
|
||||
/* Initialization */
|
||||
+ WARN_ON(!(table->valid_hooks & (1 << hook)));
|
||||
+ local_bh_disable();
|
||||
+ private = READ_ONCE(table->private); /* Address dependency. */
|
||||
+ cpu = smp_processor_id();
|
||||
+ 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;
|
||||
- /* 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.state = state;
|
||||
|
||||
- WARN_ON(!(table->valid_hooks & (1 << hook)));
|
||||
- local_bh_disable();
|
||||
addend = xt_write_recseq_begin();
|
||||
- private = READ_ONCE(table->private); /* Address dependency. */
|
||||
- cpu = smp_processor_id();
|
||||
- table_base = private->entries;
|
||||
jumpstack = (struct ipt_entry **)private->jumpstack[cpu];
|
||||
|
||||
/* Switch to alternate jumpstack if we're being invoked via TEE.
|
||||
@@ -299,7 +327,16 @@ 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.state = state;
|
||||
|
||||
do {
|
||||
const struct xt_entry_target *t;
|
||||
@@ -0,0 +1,22 @@
|
||||
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(-)
|
||||
|
||||
--- a/net/ipv4/netfilter/ip_tables.c
|
||||
+++ b/net/ipv4/netfilter/ip_tables.c
|
||||
@@ -53,9 +53,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;
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
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(+)
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_proto_tcp.c
|
||||
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
|
||||
@@ -31,6 +31,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. */
|
||||
@@ -476,6 +479,9 @@ static bool tcp_in_window(const struct n
|
||||
s32 receiver_offset;
|
||||
bool res, in_recv_win;
|
||||
|
||||
+ if (nf_ct_tcp_no_window_check)
|
||||
+ return true;
|
||||
+
|
||||
/*
|
||||
* Get the required data from the packet.
|
||||
*/
|
||||
@@ -1130,7 +1136,7 @@ int nf_conntrack_tcp_packet(struct nf_co
|
||||
IP_CT_TCP_FLAG_DATA_UNACKNOWLEDGED &&
|
||||
timeouts[new_state] > timeouts[TCP_CONNTRACK_UNACK])
|
||||
timeout = timeouts[TCP_CONNTRACK_UNACK];
|
||||
- else if (ct->proto.tcp.last_win == 0 &&
|
||||
+ else if (!nf_ct_tcp_no_window_check && ct->proto.tcp.last_win == 0 &&
|
||||
timeouts[new_state] > timeouts[TCP_CONNTRACK_RETRANS])
|
||||
timeout = timeouts[TCP_CONNTRACK_RETRANS];
|
||||
else
|
||||
--- a/net/netfilter/nf_conntrack_standalone.c
|
||||
+++ b/net/netfilter/nf_conntrack_standalone.c
|
||||
@@ -25,6 +25,9 @@
|
||||
#include <net/netfilter/nf_conntrack_timestamp.h>
|
||||
#include <linux/rculist_nulls.h>
|
||||
|
||||
+/* Do not check the TCP window for incoming packets */
|
||||
+static int nf_ct_tcp_no_window_check __read_mostly = 1;
|
||||
+
|
||||
static bool enable_hooks __read_mostly;
|
||||
MODULE_PARM_DESC(enable_hooks, "Always enable conntrack hooks");
|
||||
module_param(enable_hooks, bool, 0000);
|
||||
@@ -660,6 +663,7 @@ enum nf_ct_sysctl_index {
|
||||
NF_SYSCTL_CT_PROTO_TIMEOUT_GRE_STREAM,
|
||||
#endif
|
||||
|
||||
+ NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK,
|
||||
__NF_SYSCTL_CT_LAST_SYSCTL,
|
||||
};
|
||||
|
||||
@@ -1014,6 +1018,13 @@ static struct ctl_table nf_ct_sysctl_tab
|
||||
.proc_handler = proc_dointvec_jiffies,
|
||||
},
|
||||
#endif
|
||||
+ [NF_SYSCTL_CT_PROTO_TCP_NO_WINDOW_CHECK] = {
|
||||
+ .procname = "nf_conntrack_tcp_no_window_check",
|
||||
+ .data = &nf_ct_tcp_no_window_check,
|
||||
+ .maxlen = sizeof(unsigned int),
|
||||
+ .mode = 0644,
|
||||
+ .proc_handler = proc_dointvec,
|
||||
+ },
|
||||
{}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
From: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
|
||||
Date: Mon, 21 Aug 2017 11:14:14 +0300
|
||||
Subject: [PATCH] net_sched/codel: do not defer queue length update
|
||||
|
||||
When codel wants to drop last packet in ->dequeue() it cannot call
|
||||
qdisc_tree_reduce_backlog() right away - it will notify parent qdisc
|
||||
about zero qlen and HTB/HFSC will deactivate class. The same class will
|
||||
be deactivated second time by caller of ->dequeue(). Currently codel and
|
||||
fq_codel defer update. This triggers warning in HFSC when it's qlen != 0
|
||||
but there is no active classes.
|
||||
|
||||
This patch update parent queue length immediately: just temporary increase
|
||||
qlen around qdisc_tree_reduce_backlog() to prevent first class deactivation
|
||||
if we have skb to return.
|
||||
|
||||
This might open another problem in HFSC - now operation peek could fail and
|
||||
deactivate parent class.
|
||||
|
||||
Signed-off-by: Konstantin Khlebnikov <khlebnikov@yandex-team.ru>
|
||||
Link: https://bugzilla.kernel.org/show_bug.cgi?id=109581
|
||||
---
|
||||
|
||||
--- a/net/sched/sch_codel.c
|
||||
+++ b/net/sched/sch_codel.c
|
||||
@@ -95,11 +95,17 @@ static struct sk_buff *codel_qdisc_deque
|
||||
&q->stats, qdisc_pkt_len, codel_get_enqueue_time,
|
||||
drop_func, dequeue_func);
|
||||
|
||||
- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
|
||||
- * or HTB crashes. Defer it for next round.
|
||||
+ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
|
||||
+ * parent class, dequeue in parent qdisc will do the same if we
|
||||
+ * return skb. Temporary increment qlen if we have skb.
|
||||
*/
|
||||
- if (q->stats.drop_count && sch->q.qlen) {
|
||||
- qdisc_tree_reduce_backlog(sch, q->stats.drop_count, q->stats.drop_len);
|
||||
+ if (q->stats.drop_count) {
|
||||
+ if (skb)
|
||||
+ sch->q.qlen++;
|
||||
+ qdisc_tree_reduce_backlog(sch, q->stats.drop_count,
|
||||
+ q->stats.drop_len);
|
||||
+ if (skb)
|
||||
+ sch->q.qlen--;
|
||||
q->stats.drop_count = 0;
|
||||
q->stats.drop_len = 0;
|
||||
}
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -304,6 +304,21 @@ begin:
|
||||
&flow->cvars, &q->cstats, qdisc_pkt_len,
|
||||
codel_get_enqueue_time, drop_func, dequeue_func);
|
||||
|
||||
+ /* If our qlen is 0 qdisc_tree_reduce_backlog() will deactivate
|
||||
+ * parent class, dequeue in parent qdisc will do the same if we
|
||||
+ * return skb. Temporary increment qlen if we have skb.
|
||||
+ */
|
||||
+ if (q->cstats.drop_count) {
|
||||
+ if (skb)
|
||||
+ sch->q.qlen++;
|
||||
+ qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
|
||||
+ q->cstats.drop_len);
|
||||
+ if (skb)
|
||||
+ sch->q.qlen--;
|
||||
+ q->cstats.drop_count = 0;
|
||||
+ q->cstats.drop_len = 0;
|
||||
+ }
|
||||
+
|
||||
if (!skb) {
|
||||
/* force a pass through old_flows to prevent starvation */
|
||||
if ((head == &q->new_flows) && !list_empty(&q->old_flows))
|
||||
@@ -314,15 +329,6 @@ begin:
|
||||
}
|
||||
qdisc_bstats_update(sch, skb);
|
||||
flow->deficit -= qdisc_pkt_len(skb);
|
||||
- /* We cant call qdisc_tree_reduce_backlog() if our qlen is 0,
|
||||
- * or HTB crashes. Defer it for next round.
|
||||
- */
|
||||
- if (q->cstats.drop_count && sch->q.qlen) {
|
||||
- qdisc_tree_reduce_backlog(sch, q->cstats.drop_count,
|
||||
- q->cstats.drop_len);
|
||||
- q->cstats.drop_count = 0;
|
||||
- q->cstats.drop_len = 0;
|
||||
- }
|
||||
return skb;
|
||||
}
|
||||
|
||||
138
target/linux/generic/pending-5.10/630-packet_socket_type.patch
Normal file
138
target/linux/generic/pending-5.10/630-packet_socket_type.patch
Normal file
@@ -0,0 +1,138 @@
|
||||
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(-)
|
||||
|
||||
--- a/include/uapi/linux/if_packet.h
|
||||
+++ b/include/uapi/linux/if_packet.h
|
||||
@@ -33,6 +33,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 */
|
||||
|
||||
@@ -59,6 +61,7 @@ struct sockaddr_ll {
|
||||
#define PACKET_ROLLOVER_STATS 21
|
||||
#define PACKET_FANOUT_DATA 22
|
||||
#define PACKET_IGNORE_OUTGOING 23
|
||||
+#define PACKET_RECV_TYPE 24
|
||||
|
||||
#define PACKET_FANOUT_HASH 0
|
||||
#define PACKET_FANOUT_LB 1
|
||||
--- a/net/packet/af_packet.c
|
||||
+++ b/net/packet/af_packet.c
|
||||
@@ -1818,6 +1818,7 @@ static int packet_rcv_spkt(struct sk_buf
|
||||
{
|
||||
struct sock *sk;
|
||||
struct sockaddr_pkt *spkt;
|
||||
+ struct packet_sock *po;
|
||||
|
||||
/*
|
||||
* When we registered the protocol we saved the socket in the data
|
||||
@@ -1825,6 +1826,7 @@ static int packet_rcv_spkt(struct sk_buf
|
||||
*/
|
||||
|
||||
sk = pt->af_packet_priv;
|
||||
+ po = pkt_sk(sk);
|
||||
|
||||
/*
|
||||
* Yank back the headers [hope the device set this
|
||||
@@ -1837,7 +1839,7 @@ static int packet_rcv_spkt(struct sk_buf
|
||||
* 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)))
|
||||
@@ -2075,12 +2077,12 @@ static int packet_rcv(struct sk_buff *sk
|
||||
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;
|
||||
|
||||
@@ -2206,12 +2208,12 @@ static int tpacket_rcv(struct sk_buff *s
|
||||
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;
|
||||
|
||||
@@ -3318,6 +3320,7 @@ static int packet_create(struct net *net
|
||||
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;
|
||||
@@ -3954,6 +3957,16 @@ packet_setsockopt(struct socket *sock, i
|
||||
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_sockptr(&val, optval, sizeof(val)))
|
||||
+ return -EFAULT;
|
||||
+ po->pkt_type = val & ~BIT(PACKET_LOOPBACK);
|
||||
+ return 0;
|
||||
+ }
|
||||
default:
|
||||
return -ENOPROTOOPT;
|
||||
}
|
||||
@@ -4010,6 +4023,13 @@ static int packet_getsockopt(struct sock
|
||||
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;
|
||||
--- a/net/packet/internal.h
|
||||
+++ b/net/packet/internal.h
|
||||
@@ -137,6 +137,7 @@ struct packet_sock {
|
||||
int (*xmit)(struct sk_buff *skb);
|
||||
struct packet_type prot_hook ____cacheline_aligned_in_smp;
|
||||
atomic_t tp_drops ____cacheline_aligned_in_smp;
|
||||
+ unsigned int pkt_type;
|
||||
};
|
||||
|
||||
static struct packet_sock *pkt_sk(struct sock *sk)
|
||||
20
target/linux/generic/pending-5.10/655-increase_skb_pad.patch
Normal file
20
target/linux/generic/pending-5.10/655-increase_skb_pad.patch
Normal file
@@ -0,0 +1,20 @@
|
||||
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(-)
|
||||
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -2676,7 +2676,7 @@ static inline int pskb_network_may_pull(
|
||||
* 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);
|
||||
@@ -0,0 +1,511 @@
|
||||
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
|
||||
@@ -18,6 +18,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 */
|
||||
@@ -29,6 +41,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
|
||||
@@ -77,10 +77,23 @@ enum {
|
||||
IFLA_IPTUN_ENCAP_DPORT,
|
||||
IFLA_IPTUN_COLLECT_METADATA,
|
||||
IFLA_IPTUN_FWMARK,
|
||||
+ 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
|
||||
@@ -11,6 +11,9 @@
|
||||
* linux/net/ipv6/sit.c and linux/net/ipv4/ipip.c
|
||||
*
|
||||
* RFC 2473
|
||||
+ *
|
||||
+ * Changes:
|
||||
+ * Steven Barth <cyrus@openwrt.org>: MAP-E FMR support
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
@@ -67,9 +70,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);
|
||||
}
|
||||
@@ -144,17 +147,33 @@ static struct ip6_tnl *
|
||||
ip6_tnl_lookup(struct net *net, int link,
|
||||
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, *cand = NULL;
|
||||
struct ip6_tnl_net *ip6n = net_generic(net, ip6_tnl_net_id);
|
||||
struct in6_addr any;
|
||||
|
||||
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))
|
||||
continue;
|
||||
|
||||
+ if (!ipv6_addr_equal(remote, &t->parms.raddr)) {
|
||||
+ struct __ip6_tnl_fmr *fmr;
|
||||
+ bool found = false;
|
||||
+
|
||||
+ for (fmr = t->parms.fmrs; fmr; fmr = fmr->next) {
|
||||
+ if (!ipv6_prefix_equal(remote, &fmr->ip6_prefix,
|
||||
+ fmr->ip6_prefix_len))
|
||||
+ continue;
|
||||
+
|
||||
+ found = true;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ if (!found)
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
if (link == t->parms.link)
|
||||
return t;
|
||||
else
|
||||
@@ -162,7 +181,7 @@ ip6_tnl_lookup(struct net *net, int link
|
||||
}
|
||||
|
||||
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) ||
|
||||
@@ -175,7 +194,7 @@ ip6_tnl_lookup(struct net *net, int link
|
||||
cand = 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) ||
|
||||
@@ -223,7 +242,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];
|
||||
}
|
||||
@@ -405,6 +424,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
|
||||
@@ -821,6 +846,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,
|
||||
@@ -873,6 +999,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) && tunnel->parms.fmrs &&
|
||||
+ !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);
|
||||
@@ -1024,6 +1171,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
|
||||
@@ -1304,6 +1452,7 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
|
||||
u8 protocol)
|
||||
{
|
||||
struct ip6_tnl *t = netdev_priv(dev);
|
||||
+ struct __ip6_tnl_fmr *fmr;
|
||||
struct ipv6hdr *ipv6h;
|
||||
const struct iphdr *iph;
|
||||
int encap_limit = -1;
|
||||
@@ -1403,6 +1552,18 @@ ipxip6_tnl_xmit(struct sk_buff *skb, str
|
||||
fl6.flowi6_uid = sock_net_uid(dev_net(dev), NULL);
|
||||
dsfield = INET_ECN_encapsulate(dsfield, orig_dsfield);
|
||||
|
||||
+ /* 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;
|
||||
|
||||
@@ -1555,6 +1716,14 @@ ip6_tnl_change(struct ip6_tnl *t, const
|
||||
t->parms.link = p->link;
|
||||
t->parms.proto = p->proto;
|
||||
t->parms.fwmark = p->fwmark;
|
||||
+
|
||||
+ 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;
|
||||
@@ -1593,6 +1762,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));
|
||||
}
|
||||
|
||||
@@ -1978,6 +2148,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)
|
||||
{
|
||||
@@ -2015,6 +2194,46 @@ static void ip6_tnl_netlink_parms(struct
|
||||
|
||||
if (data[IFLA_IPTUN_FWMARK])
|
||||
parms->fwmark = nla_get_u32(data[IFLA_IPTUN_FWMARK]);
|
||||
+
|
||||
+ 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, NULL);
|
||||
+
|
||||
+ 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[],
|
||||
@@ -2130,6 +2349,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) +
|
||||
@@ -2159,6 +2384,24 @@ static size_t ip6_tnl_get_size(const str
|
||||
nla_total_size(0) +
|
||||
/* IFLA_IPTUN_FWMARK */
|
||||
nla_total_size(4) +
|
||||
+ /* 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;
|
||||
}
|
||||
|
||||
@@ -2166,6 +2409,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) ||
|
||||
@@ -2175,9 +2421,27 @@ static int ip6_tnl_fill_info(struct sk_b
|
||||
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_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark))
|
||||
+ nla_put_u32(skb, IFLA_IPTUN_FWMARK, parm->fwmark) ||
|
||||
+ !(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) ||
|
||||
@@ -2217,6 +2481,7 @@ static const struct nla_policy ip6_tnl_p
|
||||
[IFLA_IPTUN_ENCAP_DPORT] = { .type = NLA_U16 },
|
||||
[IFLA_IPTUN_COLLECT_METADATA] = { .type = NLA_FLAG },
|
||||
[IFLA_IPTUN_FWMARK] = { .type = NLA_U32 },
|
||||
+ [IFLA_IPTUN_FMRS] = { .type = NLA_NESTED },
|
||||
};
|
||||
|
||||
static struct rtnl_link_ops ip6_link_ops __read_mostly = {
|
||||
@@ -0,0 +1,263 @@
|
||||
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
|
||||
@@ -87,6 +87,7 @@ struct netns_ipv6 {
|
||||
unsigned int fib6_routes_require_src;
|
||||
#endif
|
||||
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
|
||||
@@ -82,6 +82,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
|
||||
@@ -249,6 +249,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
|
||||
@@ -141,6 +141,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
|
||||
@@ -2734,6 +2734,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
|
||||
@@ -175,6 +175,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
|
||||
@@ -220,6 +220,10 @@ static int __fib6_rule_action(struct fib
|
||||
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
|
||||
@@ -163,6 +163,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
|
||||
@@ -95,6 +95,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,
|
||||
@@ -310,6 +312,18 @@ static const struct rt6_info ip6_prohibi
|
||||
.rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP),
|
||||
};
|
||||
|
||||
+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),
|
||||
+};
|
||||
+
|
||||
static const struct rt6_info ip6_blk_hole_entry_template = {
|
||||
.dst = {
|
||||
.__refcnt = ATOMIC_INIT(1),
|
||||
@@ -1031,6 +1045,7 @@ static const int fib6_prop[RTN_MAX + 1]
|
||||
[RTN_BLACKHOLE] = -EINVAL,
|
||||
[RTN_UNREACHABLE] = -EHOSTUNREACH,
|
||||
[RTN_PROHIBIT] = -EACCES,
|
||||
+ [RTN_POLICY_FAILED] = -EACCES,
|
||||
[RTN_THROW] = -EAGAIN,
|
||||
[RTN_NAT] = -EINVAL,
|
||||
[RTN_XRESOLVE] = -EINVAL,
|
||||
@@ -1066,6 +1081,10 @@ static void ip6_rt_init_dst_reject(struc
|
||||
rt->dst.output = ip6_pkt_prohibit_out;
|
||||
rt->dst.input = ip6_pkt_prohibit;
|
||||
break;
|
||||
+ case RTN_POLICY_FAILED:
|
||||
+ rt->dst.output = ip6_pkt_policy_failed_out;
|
||||
+ rt->dst.input = ip6_pkt_policy_failed;
|
||||
+ break;
|
||||
case RTN_THROW:
|
||||
case RTN_UNREACHABLE:
|
||||
default:
|
||||
@@ -4429,6 +4448,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.
|
||||
*/
|
||||
@@ -4909,7 +4939,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)
|
||||
@@ -6080,6 +6111,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
|
||||
@@ -6091,6 +6124,7 @@ static int ip6_route_dev_notify(struct n
|
||||
in6_dev_put_clear(&net->ipv6.ip6_null_entry->rt6i_idev);
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
in6_dev_put_clear(&net->ipv6.ip6_prohibit_entry->rt6i_idev);
|
||||
+ in6_dev_put_clear(&net->ipv6.ip6_policy_failed_entry->rt6i_idev);
|
||||
in6_dev_put_clear(&net->ipv6.ip6_blk_hole_entry->rt6i_idev);
|
||||
#endif
|
||||
}
|
||||
@@ -6282,6 +6316,8 @@ static int __net_init ip6_route_net_init
|
||||
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
net->ipv6.fib6_has_custom_rules = false;
|
||||
+
|
||||
+
|
||||
net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
|
||||
sizeof(*net->ipv6.ip6_prohibit_entry),
|
||||
GFP_KERNEL);
|
||||
@@ -6292,11 +6328,21 @@ static int __net_init ip6_route_net_init
|
||||
ip6_template_metrics, true);
|
||||
INIT_LIST_HEAD(&net->ipv6.ip6_prohibit_entry->rt6i_uncached);
|
||||
|
||||
+ 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_prohibit_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);
|
||||
+ INIT_LIST_HEAD(&net->ipv6.ip6_policy_failed_entry->rt6i_uncached);
|
||||
+
|
||||
net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
|
||||
sizeof(*net->ipv6.ip6_blk_hole_entry),
|
||||
GFP_KERNEL);
|
||||
if (!net->ipv6.ip6_blk_hole_entry)
|
||||
- goto out_ip6_prohibit_entry;
|
||||
+ goto out_ip6_policy_failed_entry;
|
||||
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);
|
||||
@@ -6323,6 +6369,8 @@ out:
|
||||
return ret;
|
||||
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
+out_ip6_policy_failed_entry:
|
||||
+ kfree(net->ipv6.ip6_policy_failed_entry);
|
||||
out_ip6_prohibit_entry:
|
||||
kfree(net->ipv6.ip6_prohibit_entry);
|
||||
out_ip6_null_entry:
|
||||
@@ -6342,6 +6390,7 @@ static void __net_exit ip6_route_net_exi
|
||||
kfree(net->ipv6.ip6_null_entry);
|
||||
#ifdef CONFIG_IPV6_MULTIPLE_TABLES
|
||||
kfree(net->ipv6.ip6_prohibit_entry);
|
||||
+ kfree(net->ipv6.ip6_policy_failed_entry);
|
||||
kfree(net->ipv6.ip6_blk_hole_entry);
|
||||
#endif
|
||||
dst_entries_destroy(&net->ipv6.ip6_dst_ops);
|
||||
@@ -6419,6 +6468,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
|
||||
@@ -89,6 +89,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
|
||||
@@ -126,6 +126,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
|
||||
@@ -253,6 +253,8 @@ enum {
|
||||
__RTN_MAX
|
||||
};
|
||||
|
||||
+#define RTN_FAILED_POLICY RTN_POLICY_FAILED
|
||||
+
|
||||
#define RTN_MAX (__RTN_MAX - 1)
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
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(-)
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -2036,6 +2036,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
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -858,6 +858,7 @@ struct sk_buff {
|
||||
#ifdef CONFIG_TLS_DEVICE
|
||||
__u8 decrypted:1;
|
||||
#endif
|
||||
+ __u8 gro_skip:1;
|
||||
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
__u16 tc_index; /* traffic control index */
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -6050,6 +6050,9 @@ static enum gro_result dev_gro_receive(s
|
||||
int same_flow;
|
||||
int grow;
|
||||
|
||||
+ if (skb->gro_skip)
|
||||
+ goto normal;
|
||||
+
|
||||
if (netif_elide_gro(skb->dev))
|
||||
goto normal;
|
||||
|
||||
@@ -8027,6 +8030,48 @@ static void __netdev_adjacent_dev_unlink
|
||||
&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,
|
||||
@@ -8078,6 +8123,7 @@ static int __netdev_upper_dev_link(struc
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ netdev_update_addr_mask(dev);
|
||||
ret = call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
ret = notifier_to_errno(ret);
|
||||
@@ -8174,6 +8220,7 @@ static void __netdev_upper_dev_unlink(st
|
||||
|
||||
__netdev_adjacent_dev_unlink_neighbour(dev, upper_dev);
|
||||
|
||||
+ netdev_update_addr_mask(dev);
|
||||
call_netdevice_notifiers_info(NETDEV_CHANGEUPPER,
|
||||
&changeupper_info.info);
|
||||
|
||||
@@ -8960,6 +9007,7 @@ int dev_set_mac_address(struct net_devic
|
||||
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;
|
||||
--- a/net/ethernet/eth.c
|
||||
+++ b/net/ethernet/eth.c
|
||||
@@ -143,6 +143,18 @@ u32 eth_get_headlen(const struct net_dev
|
||||
}
|
||||
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
|
||||
@@ -174,6 +186,10 @@ __be16 eth_type_trans(struct sk_buff *sk
|
||||
} else {
|
||||
skb->pkt_type = PACKET_OTHERHOST;
|
||||
}
|
||||
+
|
||||
+ if (eth_check_local_mask(eth->h_dest, dev->dev_addr,
|
||||
+ dev->local_addr_mask))
|
||||
+ skb->gro_skip = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -0,0 +1,79 @@
|
||||
From 639dba857aa554f2a78572adc4cf3c32de9ec2e2 Mon Sep 17 00:00:00 2001
|
||||
From: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
Date: Tue, 30 Mar 2021 18:21:14 +0200
|
||||
Subject: [PATCH 2/2] of_net: add mac-address-increment support
|
||||
|
||||
Lots of embedded devices use the mac-address of other interface
|
||||
extracted from nvmem cells and increments it by one or two. Add two
|
||||
bindings to integrate this and directly use the right mac-address for
|
||||
the interface. Some example are some routers that use the gmac
|
||||
mac-address stored in the art partition and increments it by one for the
|
||||
wifi. mac-address-increment-byte bindings is used to tell what byte of
|
||||
the mac-address has to be increased (if not defined the last byte is
|
||||
increased) and mac-address-increment tells how much the byte decided
|
||||
early has to be increased.
|
||||
|
||||
Signed-off-by: Ansuel Smith <ansuelsmth@gmail.com>
|
||||
---
|
||||
drivers/of/of_net.c | 59 ++++++++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 45 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/of/of_net.c
|
||||
+++ b/drivers/of/of_net.c
|
||||
@@ -115,27 +115,52 @@ static int of_get_mac_addr_nvmem(struct
|
||||
* this case, the real MAC is in 'local-mac-address', and 'mac-address' exists
|
||||
* but is all zeros.
|
||||
*
|
||||
+ * DT can tell the system to increment the mac-address after is extracted by
|
||||
+ * using:
|
||||
+ * - mac-address-increment-byte to decide what byte to increase
|
||||
+ * (if not defined is increased the last byte)
|
||||
+ * - mac-address-increment to decide how much to increase. The value will
|
||||
+ * not overflow to other bytes if the increment is over 255.
|
||||
+ * (example 00:01:02:03:04:ff + 1 == 00:01:02:03:04:00)
|
||||
+ *
|
||||
* Return: 0 on success and errno in case of error.
|
||||
*/
|
||||
int of_get_mac_address(struct device_node *np, u8 *addr)
|
||||
{
|
||||
+ u32 inc_idx, mac_inc;
|
||||
int ret;
|
||||
|
||||
+ /* Check first if the increment byte is present and valid.
|
||||
+ * If not set assume to increment the last byte if found.
|
||||
+ */
|
||||
+ if (of_property_read_u32(np, "mac-address-increment-byte", &inc_idx))
|
||||
+ inc_idx = 5;
|
||||
+ if (inc_idx < 3 || inc_idx > 5)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
if (!np)
|
||||
return -ENODEV;
|
||||
|
||||
ret = of_get_mac_addr(np, "mac-address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
|
||||
ret = of_get_mac_addr(np, "local-mac-address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
|
||||
ret = of_get_mac_addr(np, "address", addr);
|
||||
if (!ret)
|
||||
- return 0;
|
||||
+ goto found;
|
||||
+
|
||||
+ ret = of_get_mac_addr_nvmem(np, addr);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+found:
|
||||
+ if (!of_property_read_u32(np, "mac-address-increment", &mac_inc))
|
||||
+ addr[inc_idx] += mac_inc;
|
||||
|
||||
- return of_get_mac_addr_nvmem(np, addr);
|
||||
+ return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_mac_address);
|
||||
@@ -0,0 +1,38 @@
|
||||
--- a/drivers/of/of_net.c
|
||||
+++ b/drivers/of/of_net.c
|
||||
@@ -95,6 +95,27 @@ static int of_get_mac_addr_nvmem(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int of_add_mac_address(struct device_node *np, u8* addr)
|
||||
+{
|
||||
+ struct property *prop;
|
||||
+
|
||||
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
|
||||
+ if (!prop)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ prop->name = "mac-address";
|
||||
+ prop->length = ETH_ALEN;
|
||||
+ prop->value = kmemdup(addr, ETH_ALEN, GFP_KERNEL);
|
||||
+ if (!prop->value || of_update_property(np, prop))
|
||||
+ goto free;
|
||||
+
|
||||
+ return 0;
|
||||
+free:
|
||||
+ kfree(prop->value);
|
||||
+ kfree(prop);
|
||||
+ return -ENOMEM;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* 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
|
||||
@@ -161,6 +182,7 @@ found:
|
||||
if (!of_property_read_u32(np, "mac-address-increment", &mac_inc))
|
||||
addr[inc_idx] += mac_inc;
|
||||
|
||||
+ of_add_mac_address(np, addr);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(of_get_mac_address);
|
||||
@@ -0,0 +1,26 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 8 Jul 2021 07:08:29 +0200
|
||||
Subject: [PATCH] net: ethernet: mtk_eth_soc: avoid creating duplicate offload
|
||||
entries
|
||||
|
||||
Sometimes multiple CLS_REPLACE calls are issued for the same connection.
|
||||
rhashtable_insert_fast does not check for these duplicates, so multiple
|
||||
hardware flow entries can be created.
|
||||
Fix this by checking for an existing entry early
|
||||
|
||||
Fixes: 502e84e2382d ("net: ethernet: mtk_eth_soc: add flow offloading support")
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
+++ b/drivers/net/ethernet/mediatek/mtk_ppe_offload.c
|
||||
@@ -187,6 +187,9 @@ mtk_flow_offload_replace(struct mtk_eth
|
||||
int hash;
|
||||
int i;
|
||||
|
||||
+ if (rhashtable_lookup(ð->flow_table, &f->cookie, mtk_flow_ht_params))
|
||||
+ return -EEXIST;
|
||||
+
|
||||
if (flow_rule_match_key(rule, FLOW_DISSECTOR_KEY_META)) {
|
||||
struct flow_match_meta match;
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
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(+)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1651,6 +1651,9 @@ void phy_detach(struct phy_device *phyde
|
||||
struct module *ndev_owner = NULL;
|
||||
struct mii_bus *bus;
|
||||
|
||||
+ if (phydev->drv && phydev->drv->detach)
|
||||
+ phydev->drv->detach(phydev);
|
||||
+
|
||||
if (phydev->sysfs_links) {
|
||||
if (dev)
|
||||
sysfs_remove_link(&dev->dev.kobj, "phydev");
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -761,6 +761,12 @@ struct phy_driver {
|
||||
/** @handle_interrupt: Override default interrupt handling */
|
||||
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
|
||||
|
||||
+ /*
|
||||
+ * Called before an ethernet device is detached
|
||||
+ * from the PHY.
|
||||
+ */
|
||||
+ void (*detach)(struct phy_device *phydev);
|
||||
+
|
||||
/** @remove: Clears up any memory if needed */
|
||||
void (*remove)(struct phy_device *phydev);
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 27 Aug 2021 12:22:32 +0200
|
||||
Subject: [PATCH] bridge: add knob for filtering rx/tx BPDU packets on a port
|
||||
|
||||
Some devices (e.g. wireless APs) can't have devices behind them be part of
|
||||
a bridge topology with redundant links, due to address limitations.
|
||||
Additionally, broadcast traffic on these devices is somewhat expensive, due to
|
||||
the low data rate and wakeups of clients in powersave mode.
|
||||
This knob can be used to ensure that BPDU packets are never sent or forwarded
|
||||
to/from these devices
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/linux/if_bridge.h
|
||||
+++ b/include/linux/if_bridge.h
|
||||
@@ -56,6 +56,7 @@ struct br_ip_list {
|
||||
#define BR_MRP_AWARE BIT(17)
|
||||
#define BR_MRP_LOST_CONT BIT(18)
|
||||
#define BR_MRP_LOST_IN_CONT BIT(19)
|
||||
+#define BR_BPDU_FILTER BIT(20)
|
||||
|
||||
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||
|
||||
--- a/net/bridge/br_forward.c
|
||||
+++ b/net/bridge/br_forward.c
|
||||
@@ -191,6 +191,7 @@ out:
|
||||
void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
|
||||
{
|
||||
+ const unsigned char *dest = eth_hdr(skb)->h_dest;
|
||||
struct net_bridge_port *prev = NULL;
|
||||
struct net_bridge_port *p;
|
||||
|
||||
@@ -206,6 +207,10 @@ void br_flood(struct net_bridge *br, str
|
||||
case BR_PKT_MULTICAST:
|
||||
if (!(p->flags & BR_MCAST_FLOOD) && skb->dev != br->dev)
|
||||
continue;
|
||||
+ if ((p->flags & BR_BPDU_FILTER) &&
|
||||
+ unlikely(is_link_local_ether_addr(dest) &&
|
||||
+ dest[5] == 0))
|
||||
+ continue;
|
||||
break;
|
||||
case BR_PKT_BROADCAST:
|
||||
if (!(p->flags & BR_BCAST_FLOOD) && skb->dev != br->dev)
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -305,6 +305,8 @@ static rx_handler_result_t br_handle_fra
|
||||
fwd_mask |= p->group_fwd_mask;
|
||||
switch (dest[5]) {
|
||||
case 0x00: /* Bridge Group Address */
|
||||
+ if (p->flags & BR_BPDU_FILTER)
|
||||
+ goto drop;
|
||||
/* If STP is turned off,
|
||||
then must forward to keep loop detection */
|
||||
if (p->br->stp_enabled == BR_NO_STP ||
|
||||
--- a/net/bridge/br_sysfs_if.c
|
||||
+++ b/net/bridge/br_sysfs_if.c
|
||||
@@ -233,6 +233,7 @@ BRPORT_ATTR_FLAG(multicast_flood, BR_MCA
|
||||
BRPORT_ATTR_FLAG(broadcast_flood, BR_BCAST_FLOOD);
|
||||
BRPORT_ATTR_FLAG(neigh_suppress, BR_NEIGH_SUPPRESS);
|
||||
BRPORT_ATTR_FLAG(isolated, BR_ISOLATED);
|
||||
+BRPORT_ATTR_FLAG(bpdu_filter, BR_BPDU_FILTER);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
@@ -285,6 +286,7 @@ static const struct brport_attribute *br
|
||||
&brport_attr_group_fwd_mask,
|
||||
&brport_attr_neigh_suppress,
|
||||
&brport_attr_isolated,
|
||||
+ &brport_attr_bpdu_filter,
|
||||
&brport_attr_backup_port,
|
||||
NULL
|
||||
};
|
||||
--- a/net/bridge/br_stp_bpdu.c
|
||||
+++ b/net/bridge/br_stp_bpdu.c
|
||||
@@ -80,7 +80,8 @@ void br_send_config_bpdu(struct net_brid
|
||||
{
|
||||
unsigned char buf[35];
|
||||
|
||||
- if (p->br->stp_enabled != BR_KERNEL_STP)
|
||||
+ if (p->br->stp_enabled != BR_KERNEL_STP ||
|
||||
+ (p->flags & BR_BPDU_FILTER))
|
||||
return;
|
||||
|
||||
buf[0] = 0;
|
||||
@@ -127,7 +128,8 @@ void br_send_tcn_bpdu(struct net_bridge_
|
||||
{
|
||||
unsigned char buf[4];
|
||||
|
||||
- if (p->br->stp_enabled != BR_KERNEL_STP)
|
||||
+ if (p->br->stp_enabled != BR_KERNEL_STP ||
|
||||
+ (p->flags & BR_BPDU_FILTER))
|
||||
return;
|
||||
|
||||
buf[0] = 0;
|
||||
@@ -172,6 +174,9 @@ void br_stp_rcv(const struct stp_proto *
|
||||
if (!(br->dev->flags & IFF_UP))
|
||||
goto out;
|
||||
|
||||
+ if (p->flags & BR_BPDU_FILTER)
|
||||
+ goto out;
|
||||
+
|
||||
if (p->state == BR_STATE_DISABLED)
|
||||
goto out;
|
||||
|
||||
--- a/include/uapi/linux/if_link.h
|
||||
+++ b/include/uapi/linux/if_link.h
|
||||
@@ -524,6 +524,7 @@ enum {
|
||||
IFLA_BRPORT_BACKUP_PORT,
|
||||
IFLA_BRPORT_MRP_RING_OPEN,
|
||||
IFLA_BRPORT_MRP_IN_OPEN,
|
||||
+ IFLA_BRPORT_BPDU_FILTER,
|
||||
__IFLA_BRPORT_MAX
|
||||
};
|
||||
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||
--- a/net/bridge/br_netlink.c
|
||||
+++ b/net/bridge/br_netlink.c
|
||||
@@ -137,6 +137,7 @@ static inline size_t br_port_info_size(v
|
||||
+ nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */
|
||||
+ nla_total_size(1) /* IFLA_BRPORT_NEIGH_SUPPRESS */
|
||||
+ nla_total_size(1) /* IFLA_BRPORT_ISOLATED */
|
||||
+ + nla_total_size(1) /* IFLA_BRPORT_BPDU_FILTER */
|
||||
+ nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */
|
||||
+ nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */
|
||||
+ nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */
|
||||
@@ -220,7 +221,8 @@ static int br_port_fill_attrs(struct sk_
|
||||
BR_MRP_LOST_CONT)) ||
|
||||
nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN,
|
||||
!!(p->flags & BR_MRP_LOST_IN_CONT)) ||
|
||||
- nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)))
|
||||
+ nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)) ||
|
||||
+ nla_put_u8(skb, IFLA_BRPORT_BPDU_FILTER, !!(p->flags & BR_BPDU_FILTER)))
|
||||
return -EMSGSIZE;
|
||||
|
||||
timerval = br_timer_value(&p->message_age_timer);
|
||||
@@ -728,6 +730,7 @@ static const struct nla_policy br_port_p
|
||||
[IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NLA_U8 },
|
||||
[IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 },
|
||||
[IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 },
|
||||
+ [IFLA_BRPORT_BPDU_FILTER] = { .type = NLA_U8 },
|
||||
};
|
||||
|
||||
/* Change the state of the port and notify spanning tree */
|
||||
@@ -826,6 +829,10 @@ static int br_setport(struct net_bridge_
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
+ err = br_set_port_flag(p, tb, IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false;
|
||||
err = br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
|
||||
if (err)
|
||||
--- a/net/core/rtnetlink.c
|
||||
+++ b/net/core/rtnetlink.c
|
||||
@@ -55,7 +55,7 @@
|
||||
#include <net/net_namespace.h>
|
||||
|
||||
#define RTNL_MAX_TYPE 50
|
||||
-#define RTNL_SLAVE_MAX_TYPE 36
|
||||
+#define RTNL_SLAVE_MAX_TYPE 37
|
||||
|
||||
struct rtnl_link {
|
||||
rtnl_doit_func doit;
|
||||
@@ -4680,7 +4680,9 @@ int ndo_dflt_bridge_getlink(struct sk_bu
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD) ||
|
||||
brport_nla_put_flag(skb, flags, mask,
|
||||
- IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD)) {
|
||||
+ IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD) ||
|
||||
+ brport_nla_put_flag(skb, flags, mask,
|
||||
+ IFLA_BRPORT_BPDU_FILTER, BR_BPDU_FILTER)) {
|
||||
nla_nest_cancel(skb, protinfo);
|
||||
goto nla_put_failure;
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
From 97ca310aa18a93329ef5cd68c20de89761962f45 Mon Sep 17 00:00:00 2001
|
||||
From: David Bauer <mail@david-bauer.net>
|
||||
Date: Sun, 13 Jun 2021 12:19:36 +0200
|
||||
Subject: [PATCH] net: phy: at803x: fix feature detection
|
||||
|
||||
AR8031/AR8033 have different status registers for copper
|
||||
and fiber operation. However, the extended status register
|
||||
is the same for both operation modes.
|
||||
|
||||
As a result of that, ESTATUS_1000_XFULL is set to 1 even when
|
||||
operating in copper TP mode.
|
||||
|
||||
Remove this mode from the supported link modes, as this driver
|
||||
currently only supports copper operation.
|
||||
|
||||
Signed-off-by: David Bauer <mail@david-bauer.net>
|
||||
---
|
||||
drivers/net/phy/at803x.c | 30 +++++++++++++++++++++++++++++-
|
||||
1 file changed, 29 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -935,6 +935,34 @@ static int at803x_set_tunable(struct phy
|
||||
}
|
||||
}
|
||||
|
||||
+static int at803x_get_features(struct phy_device *phydev)
|
||||
+{
|
||||
+ int err;
|
||||
+
|
||||
+ err = genphy_read_abilities(phydev);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!at803x_match_phy_id(phydev, ATH8031_PHY_ID))
|
||||
+ return 0;
|
||||
+
|
||||
+ /* AR8031/AR8033 have different status registers
|
||||
+ * for copper and fiber operation. However, the
|
||||
+ * extended status register is the same for both
|
||||
+ * operation modes.
|
||||
+ *
|
||||
+ * As a result of that, ESTATUS_1000_XFULL is set
|
||||
+ * to 1 even when operating in copper TP mode.
|
||||
+ *
|
||||
+ * Remove this mode from the supported link modes,
|
||||
+ * as this driver currently only supports copper
|
||||
+ * operation.
|
||||
+ */
|
||||
+ linkmode_clear_bit(ETHTOOL_LINK_MODE_1000baseX_Full_BIT,
|
||||
+ phydev->supported);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int at803x_cable_test_result_trans(u16 status)
|
||||
{
|
||||
switch (FIELD_GET(AT803X_CDT_STATUS_STAT_MASK, status)) {
|
||||
@@ -1156,7 +1184,7 @@ static struct phy_driver at803x_driver[]
|
||||
.resume = at803x_resume,
|
||||
.read_page = at803x_read_page,
|
||||
.write_page = at803x_write_page,
|
||||
- /* PHY_GBIT_FEATURES */
|
||||
+ .get_features = at803x_get_features,
|
||||
.read_status = at803x_read_status,
|
||||
.aneg_done = at803x_aneg_done,
|
||||
.ack_interrupt = &at803x_ack_interrupt,
|
||||
@@ -0,0 +1,27 @@
|
||||
From a1b291f3f6c80a6c5ccad7283fc472d77a2a4763 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sun, 22 Dec 2019 12:40:11 +0000
|
||||
Subject: [PATCH] net: dsa: mv88e6xxx: fix vlan setup
|
||||
|
||||
Provide an option that drivers can set to indicate they want to receive
|
||||
vlan configuration even when vlan filtering is disabled. This is safe
|
||||
for Marvell DSA bridges, which do not look up ingress traffic in the
|
||||
VTU if the port is in 8021Q disabled state. Whether this change is
|
||||
suitable for all DSA bridges is not known.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Signed-off-by: DENG Qingfang <dqfext@gmail.com>
|
||||
---
|
||||
drivers/net/dsa/mv88e6xxx/chip.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/net/dsa/mv88e6xxx/chip.c
|
||||
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
|
||||
@@ -2860,6 +2860,7 @@ static int mv88e6xxx_setup(struct dsa_sw
|
||||
|
||||
chip->ds = ds;
|
||||
ds->slave_mii_bus = mv88e6xxx_default_mdio_bus(chip);
|
||||
+ ds->configure_vlan_while_not_filtering = true;
|
||||
|
||||
mv88e6xxx_reg_lock(chip);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
From 46fe6cecb296d850c1ee2b333e57093ac4b733f3 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:09 +0100
|
||||
Subject: [PATCH] net: bridge: switchdev: Refactor br_switchdev_fdb_notify
|
||||
|
||||
Instead of having to add more and more arguments to
|
||||
br_switchdev_fdb_call_notifiers, get rid of it and build the info
|
||||
struct directly in br_switchdev_fdb_notify.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Reviewed-by: Vladimir Oltean <olteanv@gmail.com>
|
||||
---
|
||||
net/bridge/br_switchdev.c | 41 +++++++++++----------------------------
|
||||
1 file changed, 11 insertions(+), 30 deletions(-)
|
||||
|
||||
--- a/net/bridge/br_switchdev.c
|
||||
+++ b/net/bridge/br_switchdev.c
|
||||
@@ -102,25 +102,16 @@ int br_switchdev_set_port_flag(struct ne
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static void
|
||||
-br_switchdev_fdb_call_notifiers(bool adding, const unsigned char *mac,
|
||||
- u16 vid, struct net_device *dev,
|
||||
- bool added_by_user, bool offloaded)
|
||||
-{
|
||||
- struct switchdev_notifier_fdb_info info;
|
||||
- unsigned long notifier_type;
|
||||
-
|
||||
- info.addr = mac;
|
||||
- info.vid = vid;
|
||||
- info.added_by_user = added_by_user;
|
||||
- info.offloaded = offloaded;
|
||||
- notifier_type = adding ? SWITCHDEV_FDB_ADD_TO_DEVICE : SWITCHDEV_FDB_DEL_TO_DEVICE;
|
||||
- call_switchdev_notifiers(notifier_type, dev, &info.info, NULL);
|
||||
-}
|
||||
-
|
||||
void
|
||||
br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
|
||||
{
|
||||
+ struct switchdev_notifier_fdb_info info = {
|
||||
+ .addr = fdb->key.addr.addr,
|
||||
+ .vid = fdb->key.vlan_id,
|
||||
+ .added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags),
|
||||
+ .offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
|
||||
+ };
|
||||
+
|
||||
if (!fdb->dst)
|
||||
return;
|
||||
if (test_bit(BR_FDB_LOCAL, &fdb->flags))
|
||||
@@ -128,22 +119,12 @@ br_switchdev_fdb_notify(const struct net
|
||||
|
||||
switch (type) {
|
||||
case RTM_DELNEIGH:
|
||||
- br_switchdev_fdb_call_notifiers(false, fdb->key.addr.addr,
|
||||
- fdb->key.vlan_id,
|
||||
- fdb->dst->dev,
|
||||
- test_bit(BR_FDB_ADDED_BY_USER,
|
||||
- &fdb->flags),
|
||||
- test_bit(BR_FDB_OFFLOADED,
|
||||
- &fdb->flags));
|
||||
+ call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
|
||||
+ fdb->dst->dev, &info.info, NULL);
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
- br_switchdev_fdb_call_notifiers(true, fdb->key.addr.addr,
|
||||
- fdb->key.vlan_id,
|
||||
- fdb->dst->dev,
|
||||
- test_bit(BR_FDB_ADDED_BY_USER,
|
||||
- &fdb->flags),
|
||||
- test_bit(BR_FDB_OFFLOADED,
|
||||
- &fdb->flags));
|
||||
+ call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
|
||||
+ fdb->dst->dev, &info.info, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
From ec5be4f79026282925ae383caa431a8d41e3456a Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:10 +0100
|
||||
Subject: [PATCH] net: bridge: switchdev: Include local flag in FDB
|
||||
notifications
|
||||
|
||||
Some switchdev drivers, notably DSA, ignore all dynamically learned
|
||||
address notifications (!added_by_user) as these are autonomously added
|
||||
by the switch. Previously, such a notification was indistinguishable
|
||||
from a local address notification. Include a local bit in the
|
||||
notification so that the two classes can be discriminated.
|
||||
|
||||
This allows DSA-like devices to add local addresses to the hardware
|
||||
FDB (with the CPU as the destination), thereby avoiding flows towards
|
||||
the CPU being flooded by the switch as unknown unicast.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
include/net/switchdev.h | 1 +
|
||||
net/bridge/br_switchdev.c | 1 +
|
||||
2 files changed, 2 insertions(+)
|
||||
|
||||
--- a/include/net/switchdev.h
|
||||
+++ b/include/net/switchdev.h
|
||||
@@ -224,6 +224,7 @@ struct switchdev_notifier_fdb_info {
|
||||
const unsigned char *addr;
|
||||
u16 vid;
|
||||
u8 added_by_user:1,
|
||||
+ local:1,
|
||||
offloaded:1;
|
||||
};
|
||||
|
||||
--- a/net/bridge/br_switchdev.c
|
||||
+++ b/net/bridge/br_switchdev.c
|
||||
@@ -109,6 +109,7 @@ br_switchdev_fdb_notify(const struct net
|
||||
.addr = fdb->key.addr.addr,
|
||||
.vid = fdb->key.vlan_id,
|
||||
.added_by_user = test_bit(BR_FDB_ADDED_BY_USER, &fdb->flags),
|
||||
+ .local = test_bit(BR_FDB_LOCAL, &fdb->flags),
|
||||
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
|
||||
};
|
||||
|
||||
@@ -0,0 +1,96 @@
|
||||
From 2e50fd9322047253c327550b4485cf8761035a8c Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:11 +0100
|
||||
Subject: [PATCH] net: bridge: switchdev: Send FDB notifications for host
|
||||
addresses
|
||||
|
||||
Treat addresses added to the bridge itself in the same way as regular
|
||||
ports and send out a notification so that drivers may sync it down to
|
||||
the hardware FDB.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
net/bridge/br_fdb.c | 4 ++--
|
||||
net/bridge/br_private.h | 7 ++++---
|
||||
net/bridge/br_switchdev.c | 11 +++++------
|
||||
3 files changed, 11 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/net/bridge/br_fdb.c
|
||||
+++ b/net/bridge/br_fdb.c
|
||||
@@ -602,7 +602,7 @@ void br_fdb_update(struct net_bridge *br
|
||||
/* fastpath: update of existing entry */
|
||||
if (unlikely(source != fdb->dst &&
|
||||
!test_bit(BR_FDB_STICKY, &fdb->flags))) {
|
||||
- br_switchdev_fdb_notify(fdb, RTM_DELNEIGH);
|
||||
+ br_switchdev_fdb_notify(br, fdb, RTM_DELNEIGH);
|
||||
fdb->dst = source;
|
||||
fdb_modified = true;
|
||||
/* Take over HW learned entry */
|
||||
@@ -735,7 +735,7 @@ static void fdb_notify(struct net_bridge
|
||||
int err = -ENOBUFS;
|
||||
|
||||
if (swdev_notify)
|
||||
- br_switchdev_fdb_notify(fdb, type);
|
||||
+ br_switchdev_fdb_notify(br, fdb, type);
|
||||
|
||||
skb = nlmsg_new(fdb_nlmsg_size(), GFP_ATOMIC);
|
||||
if (skb == NULL)
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -1527,8 +1527,8 @@ bool nbp_switchdev_allowed_egress(const
|
||||
int br_switchdev_set_port_flag(struct net_bridge_port *p,
|
||||
unsigned long flags,
|
||||
unsigned long mask);
|
||||
-void br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb,
|
||||
- int type);
|
||||
+void br_switchdev_fdb_notify(struct net_bridge *br,
|
||||
+ const struct net_bridge_fdb_entry *fdb, int type);
|
||||
int br_switchdev_port_vlan_add(struct net_device *dev, u16 vid, u16 flags,
|
||||
struct netlink_ext_ack *extack);
|
||||
int br_switchdev_port_vlan_del(struct net_device *dev, u16 vid);
|
||||
@@ -1574,7 +1574,8 @@ static inline int br_switchdev_port_vlan
|
||||
}
|
||||
|
||||
static inline void
|
||||
-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
|
||||
+br_switchdev_fdb_notify(struct net_bridge *br,
|
||||
+ const struct net_bridge_fdb_entry *fdb, int type)
|
||||
{
|
||||
}
|
||||
|
||||
--- a/net/bridge/br_switchdev.c
|
||||
+++ b/net/bridge/br_switchdev.c
|
||||
@@ -103,7 +103,8 @@ int br_switchdev_set_port_flag(struct ne
|
||||
}
|
||||
|
||||
void
|
||||
-br_switchdev_fdb_notify(const struct net_bridge_fdb_entry *fdb, int type)
|
||||
+br_switchdev_fdb_notify(struct net_bridge *br,
|
||||
+ const struct net_bridge_fdb_entry *fdb, int type)
|
||||
{
|
||||
struct switchdev_notifier_fdb_info info = {
|
||||
.addr = fdb->key.addr.addr,
|
||||
@@ -112,20 +113,19 @@ br_switchdev_fdb_notify(const struct net
|
||||
.local = test_bit(BR_FDB_LOCAL, &fdb->flags),
|
||||
.offloaded = test_bit(BR_FDB_OFFLOADED, &fdb->flags),
|
||||
};
|
||||
+ struct net_device *dev = fdb->dst ? fdb->dst->dev : br->dev;
|
||||
|
||||
- if (!fdb->dst)
|
||||
- return;
|
||||
if (test_bit(BR_FDB_LOCAL, &fdb->flags))
|
||||
return;
|
||||
|
||||
switch (type) {
|
||||
case RTM_DELNEIGH:
|
||||
call_switchdev_notifiers(SWITCHDEV_FDB_DEL_TO_DEVICE,
|
||||
- fdb->dst->dev, &info.info, NULL);
|
||||
+ dev, &info.info, NULL);
|
||||
break;
|
||||
case RTM_NEWNEIGH:
|
||||
call_switchdev_notifiers(SWITCHDEV_FDB_ADD_TO_DEVICE,
|
||||
- fdb->dst->dev, &info.info, NULL);
|
||||
+ dev, &info.info, NULL);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
From dd082716b43a3684b2f473ae5d1e76d1c076d86d Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:12 +0100
|
||||
Subject: [PATCH] net: dsa: Include local addresses in assisted CPU port
|
||||
learning
|
||||
|
||||
Add local addresses (i.e. the ports' MAC addresses) to the hardware
|
||||
FDB when assisted CPU port learning is enabled.
|
||||
|
||||
NOTE: The bridge's own MAC address is also "local". If that address is
|
||||
not shared with any port, the bridge's MAC is not be added by this
|
||||
functionality - but the following commit takes care of that case.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
net/dsa/slave.c | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2192,10 +2192,12 @@ static int dsa_slave_switchdev_event(str
|
||||
fdb_info = ptr;
|
||||
|
||||
if (dsa_slave_dev_check(dev)) {
|
||||
- if (!fdb_info->added_by_user)
|
||||
- return NOTIFY_OK;
|
||||
-
|
||||
dp = dsa_slave_to_port(dev);
|
||||
+
|
||||
+ if (fdb_info->local && dp->ds->assisted_learning_on_cpu_port)
|
||||
+ dp = dp->cpu_dp;
|
||||
+ else if (!fdb_info->added_by_user)
|
||||
+ return NOTIFY_OK;
|
||||
} else {
|
||||
/* Snoop addresses learnt on foreign interfaces
|
||||
* bridged with us, for switches that don't
|
||||
@@ -0,0 +1,30 @@
|
||||
From 0663ebde114a6fb2c28c622ba5212b302d4d2581 Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:13 +0100
|
||||
Subject: [PATCH] net: dsa: Include bridge addresses in assisted CPU port
|
||||
learning
|
||||
|
||||
Now that notifications are sent out for addresses added to the bridge
|
||||
itself, extend DSA to include those addresses in the hardware FDB when
|
||||
assisted CPU port learning is enabled.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
net/dsa/slave.c | 6 +++++-
|
||||
1 file changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2206,7 +2206,11 @@ static int dsa_slave_switchdev_event(str
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
|
||||
- br_dev = netdev_master_upper_dev_get_rcu(dev);
|
||||
+ if (netif_is_bridge_master(dev))
|
||||
+ br_dev = dev;
|
||||
+ else
|
||||
+ br_dev = netdev_master_upper_dev_get_rcu(dev);
|
||||
+
|
||||
if (!br_dev)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
From 81e39fd78db82fb51b05fff309b9c521f1a0bc5a Mon Sep 17 00:00:00 2001
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Date: Sat, 16 Jan 2021 02:25:14 +0100
|
||||
Subject: [PATCH] net: dsa: Sync static FDB entries on foreign interfaces to
|
||||
hardware
|
||||
|
||||
Reuse the "assisted_learning_on_cpu_port" functionality to always add
|
||||
entries for user-configured entries on foreign interfaces, even if
|
||||
assisted_learning_on_cpu_port is not enabled. E.g. in this situation:
|
||||
|
||||
br0
|
||||
/ \
|
||||
swp0 dummy0
|
||||
|
||||
$ bridge fdb add 02:00:de:ad:00:01 dev dummy0 vlan 1 master
|
||||
|
||||
Results in DSA adding an entry in the hardware FDB, pointing this
|
||||
address towards the CPU port.
|
||||
|
||||
The same is true for entries added to the bridge itself, e.g:
|
||||
|
||||
$ bridge fdb add 02:00:de:ad:00:01 dev br0 vlan 1 self
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
net/dsa/slave.c | 12 ++++++++----
|
||||
1 file changed, 8 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/net/dsa/slave.c
|
||||
+++ b/net/dsa/slave.c
|
||||
@@ -2199,9 +2199,12 @@ static int dsa_slave_switchdev_event(str
|
||||
else if (!fdb_info->added_by_user)
|
||||
return NOTIFY_OK;
|
||||
} else {
|
||||
- /* Snoop addresses learnt on foreign interfaces
|
||||
- * bridged with us, for switches that don't
|
||||
- * automatically learn SA from CPU-injected traffic
|
||||
+ /* Snoop addresses added to foreign interfaces
|
||||
+ * bridged with us, or the bridge
|
||||
+ * itself. Dynamically learned addresses can
|
||||
+ * also be added for switches that don't
|
||||
+ * automatically learn SA from CPU-injected
|
||||
+ * traffic.
|
||||
*/
|
||||
struct net_device *br_dev;
|
||||
struct dsa_slave_priv *p;
|
||||
@@ -2223,7 +2226,8 @@ static int dsa_slave_switchdev_event(str
|
||||
|
||||
dp = p->dp->cpu_dp;
|
||||
|
||||
- if (!dp->ds->assisted_learning_on_cpu_port)
|
||||
+ if (!fdb_info->added_by_user &&
|
||||
+ !dp->ds->assisted_learning_on_cpu_port)
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
From: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
Subject: [RFC net-next 7/7] net: dsa: mv88e6xxx: Request assisted learning on CPU port
|
||||
Date: Sat, 16 Jan 2021 02:25:15 +0100
|
||||
Archived-At: <https://lore.kernel.org/netdev/20210116012515.3152-8-tobias@waldekranz.com/>
|
||||
|
||||
While the hardware is capable of performing learning on the CPU port,
|
||||
it requires alot of additions to the bridge's forwarding path in order
|
||||
to handle multi-destination traffic correctly.
|
||||
|
||||
Until that is in place, opt for the next best thing and let DSA sync
|
||||
the relevant addresses down to the hardware FDB.
|
||||
|
||||
Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
|
||||
---
|
||||
drivers/net/dsa/mv88e6xxx/chip.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/net/dsa/mv88e6xxx/chip.c
|
||||
+++ b/drivers/net/dsa/mv88e6xxx/chip.c
|
||||
@@ -5422,6 +5422,7 @@ static int mv88e6xxx_register_switch(str
|
||||
ds->ops = &mv88e6xxx_switch_ops;
|
||||
ds->ageing_time_min = chip->info->age_time_coeff;
|
||||
ds->ageing_time_max = chip->info->age_time_coeff * U8_MAX;
|
||||
+ ds->assisted_learning_on_cpu_port = true;
|
||||
|
||||
dev_set_drvdata(dev, ds);
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
From patchwork Thu Aug 5 22:23:30 2021
|
||||
Content-Type: text/plain; charset="utf-8"
|
||||
MIME-Version: 1.0
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
|
||||
X-Patchwork-Id: 12422209
|
||||
Date: Thu, 5 Aug 2021 23:23:30 +0100
|
||||
From: Daniel Golle <daniel@makrotopia.org>
|
||||
To: linux-arm-kernel@lists.infradead.org, netdev@vger.kernel.org,
|
||||
linux-kernel@vger.kernel.org
|
||||
Cc: "David S. Miller" <davem@davemloft.net>, Andrew Lunn <andrew@lunn.ch>,
|
||||
Michael Walle <michael@walle.cc>
|
||||
Subject: [PATCH] ARM: kirkwood: add missing <linux/if_ether.h> for ETH_ALEN
|
||||
Message-ID: <YQxk4jrbm31NM1US@makrotopia.org>
|
||||
MIME-Version: 1.0
|
||||
Content-Disposition: inline
|
||||
X-BeenThere: linux-arm-kernel@lists.infradead.org
|
||||
X-Mailman-Version: 2.1.34
|
||||
Precedence: list
|
||||
List-Id: <linux-arm-kernel.lists.infradead.org>
|
||||
List-Archive: <http://lists.infradead.org/pipermail/linux-arm-kernel/>
|
||||
Sender: "linux-arm-kernel" <linux-arm-kernel-bounces@lists.infradead.org>
|
||||
|
||||
After commit 83216e3988cd1 ("of: net: pass the dst buffer to
|
||||
of_get_mac_address()") build fails for kirkwood as ETH_ALEN is not
|
||||
defined.
|
||||
|
||||
arch/arm/mach-mvebu/kirkwood.c: In function 'kirkwood_dt_eth_fixup':
|
||||
arch/arm/mach-mvebu/kirkwood.c:87:13: error: 'ETH_ALEN' undeclared (first use in this function); did you mean 'ESTALE'?
|
||||
u8 tmpmac[ETH_ALEN];
|
||||
^~~~~~~~
|
||||
ESTALE
|
||||
arch/arm/mach-mvebu/kirkwood.c:87:13: note: each undeclared identifier is reported only once for each function it appears in
|
||||
arch/arm/mach-mvebu/kirkwood.c:87:6: warning: unused variable 'tmpmac' [-Wunused-variable]
|
||||
u8 tmpmac[ETH_ALEN];
|
||||
^~~~~~
|
||||
make[5]: *** [scripts/Makefile.build:262: arch/arm/mach-mvebu/kirkwood.o] Error 1
|
||||
make[5]: *** Waiting for unfinished jobs....
|
||||
|
||||
Add missing #include <linux/if_ether.h> to fix this.
|
||||
|
||||
Cc: David S. Miller <davem@davemloft.net>
|
||||
Cc: Andrew Lunn <andrew@lunn.ch>
|
||||
Cc: Michael Walle <michael@walle.cc>
|
||||
Reported-by: https://buildbot.openwrt.org/master/images/#/builders/56/builds/220/steps/44/logs/stdio
|
||||
Fixes: 83216e3988cd1 ("of: net: pass the dst buffer to of_get_mac_address()")
|
||||
Signed-off-by: Daniel Golle <daniel@makrotopia.org>
|
||||
---
|
||||
arch/arm/mach-mvebu/kirkwood.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/arch/arm/mach-mvebu/kirkwood.c
|
||||
+++ b/arch/arm/mach-mvebu/kirkwood.c
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/mbus.h>
|
||||
+#include <linux/if_ether.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
#include <linux/of_net.h>
|
||||
@@ -0,0 +1,64 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Subject: [PATCH] bcma: get SoC device struct & copy its DMA params to the
|
||||
subdevices
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
For bus devices to be fully usable it's required to set their DMA
|
||||
parameters.
|
||||
|
||||
For years it has been missing and remained unnoticed because of
|
||||
mips_dma_alloc_coherent() silently handling the empty coherent_dma_mask.
|
||||
Kernel 4.19 came with a lot of DMA changes and caused a regression on
|
||||
the bcm47xx. Starting with the commit f8c55dc6e828 ("MIPS: use generic
|
||||
dma noncoherent ops for simple noncoherent platforms") DMA coherent
|
||||
allocations just fail. Example:
|
||||
[ 1.114914] bgmac_bcma bcma0:2: Allocation of TX ring 0x200 failed
|
||||
[ 1.121215] bgmac_bcma bcma0:2: Unable to alloc memory for DMA
|
||||
[ 1.127626] bgmac_bcma: probe of bcma0:2 failed with error -12
|
||||
[ 1.133838] bgmac_bcma: Broadcom 47xx GBit MAC driver loaded
|
||||
|
||||
This change fixes above regression in addition to the MIPS bcm47xx
|
||||
commit 321c46b91550 ("MIPS: BCM47XX: Setup struct device for the SoC").
|
||||
|
||||
It also fixes another *old* GPIO regression caused by a parent pointing
|
||||
to the NULL:
|
||||
[ 0.157054] missing gpiochip .dev parent pointer
|
||||
[ 0.157287] bcma: bus0: Error registering GPIO driver: -22
|
||||
introduced by the commit 74f4e0cc6108 ("bcma: switch GPIO portions to
|
||||
use GPIOLIB_IRQCHIP").
|
||||
|
||||
Fixes: f8c55dc6e828 ("MIPS: use generic dma noncoherent ops for simple noncoherent platforms")
|
||||
Fixes: 74f4e0cc6108 ("bcma: switch GPIO portions to use GPIOLIB_IRQCHIP")
|
||||
Cc: linux-mips@linux-mips.org
|
||||
Cc: Christoph Hellwig <hch@lst.de>
|
||||
Cc: Linus Walleij <linus.walleij@linaro.org>
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
|
||||
--- a/drivers/bcma/host_soc.c
|
||||
+++ b/drivers/bcma/host_soc.c
|
||||
@@ -191,6 +191,8 @@ int __init bcma_host_soc_init(struct bcm
|
||||
struct bcma_bus *bus = &soc->bus;
|
||||
int err;
|
||||
|
||||
+ bus->dev = soc->dev;
|
||||
+
|
||||
/* Scan bus and initialize it */
|
||||
err = bcma_bus_early_register(bus);
|
||||
if (err)
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -241,8 +241,10 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
core->dev.bus = &bcma_bus_type;
|
||||
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
||||
core->dev.parent = bus->dev;
|
||||
- if (bus->dev)
|
||||
+ if (bus->dev) {
|
||||
bcma_of_fill_device(bus->dev, core);
|
||||
+ dma_coerce_mask_and_coherent(&core->dev, bus->dev->coherent_dma_mask);
|
||||
+ }
|
||||
|
||||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
@@ -0,0 +1,62 @@
|
||||
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(+)
|
||||
|
||||
--- a/drivers/pci/Kconfig
|
||||
+++ b/drivers/pci/Kconfig
|
||||
@@ -118,6 +118,13 @@ 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 PCI_ATS
|
||||
bool
|
||||
|
||||
--- a/drivers/pci/quirks.c
|
||||
+++ b/drivers/pci/quirks.c
|
||||
@@ -206,6 +206,7 @@ static void quirk_mmio_always_on(struct
|
||||
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"
|
||||
@@ -3323,6 +3324,8 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_I
|
||||
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 work around this, query the size it should be configured to by the
|
||||
@@ -3348,6 +3351,8 @@ static void quirk_intel_ntb(struct pci_d
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e08, quirk_intel_ntb);
|
||||
DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x0e0d, quirk_intel_ntb);
|
||||
|
||||
+#ifndef CONFIG_PCI_DISABLE_COMMON_QUIRKS
|
||||
+
|
||||
/*
|
||||
* Some BIOS implementations leave the Intel GPU interrupts enabled, even
|
||||
* though no one is handling them (e.g., if the i915 driver is never
|
||||
@@ -3386,6 +3391,8 @@ DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_IN
|
||||
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.
|
||||
@@ -0,0 +1,115 @@
|
||||
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(-)
|
||||
|
||||
--- a/drivers/usb/host/pci-quirks.c
|
||||
+++ b/drivers/usb/host/pci-quirks.c
|
||||
@@ -128,6 +128,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;
|
||||
@@ -633,6 +635,10 @@ bool usb_amd_pt_check_port(struct device
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(usb_amd_pt_check_port);
|
||||
|
||||
+#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.
|
||||
@@ -712,8 +718,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;
|
||||
@@ -1285,3 +1300,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
|
||||
--- a/drivers/usb/host/pci-quirks.h
|
||||
+++ b/drivers/usb/host/pci-quirks.h
|
||||
@@ -5,6 +5,9 @@
|
||||
#ifdef CONFIG_USB_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_USB_PCI */
|
||||
+
|
||||
+#if defined(CONFIG_USB_PCI) && !defined(CONFIG_PCI_DISABLE_COMMON_QUIRKS)
|
||||
int usb_hcd_amd_remote_wakeup_quirk(struct pci_dev *pdev);
|
||||
bool usb_amd_hang_symptom_quirk(void);
|
||||
bool usb_amd_prefetch_quirk(void);
|
||||
@@ -19,6 +22,18 @@ void sb800_prefetch(struct device *dev,
|
||||
bool usb_amd_pt_check_port(struct device *device, int port);
|
||||
#else
|
||||
struct pci_dev;
|
||||
+static inline int usb_amd_quirk_pll_check(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) {}
|
||||
@@ -29,6 +44,11 @@ static inline bool usb_amd_pt_check_port
|
||||
{
|
||||
return false;
|
||||
}
|
||||
+static inline void usb_enable_intel_xhci_ports(struct pci_dev *xhci_pdev) {}
|
||||
+static inline bool usb_xhci_needs_pci_reset(struct pci_dev *pdev)
|
||||
+{
|
||||
+ return false;
|
||||
+}
|
||||
#endif /* CONFIG_USB_PCI */
|
||||
|
||||
#endif /* __LINUX_USB_PCI_QUIRKS_H */
|
||||
--- a/include/linux/usb/hcd.h
|
||||
+++ b/include/linux/usb/hcd.h
|
||||
@@ -486,7 +486,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,26 @@
|
||||
From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001
|
||||
From: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Date: Sun, 18 Feb 2018 17:08:04 +0100
|
||||
Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio
|
||||
|
||||
In devices, where fdt is used, is impossible to apply platform data
|
||||
without proper fdt node.
|
||||
|
||||
This patch allow to use platform data in devices with fdt.
|
||||
|
||||
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
---
|
||||
drivers/w1/masters/w1-gpio.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/w1/masters/w1-gpio.c
|
||||
+++ b/drivers/w1/masters/w1-gpio.c
|
||||
@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform
|
||||
enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
|
||||
int err;
|
||||
|
||||
- if (of_have_populated_dt()) {
|
||||
+ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
149
target/linux/generic/pending-5.10/834-ledtrig-libata.patch
Normal file
149
target/linux/generic/pending-5.10/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
|
||||
@@ -67,6 +67,22 @@ config ATA_FORCE
|
||||
|
||||
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
|
||||
@@ -650,6 +650,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
|
||||
@@ -4545,6 +4558,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 = qc->hw_tag = tag;
|
||||
@@ -5323,6 +5339,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;
|
||||
@@ -5358,6 +5377,12 @@ static void ata_host_release(struct kref
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -5764,7 +5789,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
|
||||
@@ -23,6 +23,9 @@
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/async.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,26 @@
|
||||
From d6988cf1d16faac56899918bb2b1be8d85155e3f Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?=C3=81lvaro=20Fern=C3=A1ndez=20Rojas?= <noltari@gmail.com>
|
||||
Date: Sat, 20 Feb 2021 18:36:38 +0100
|
||||
Subject: [PATCH] hwrng: bcm2835: set quality to 1000
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This allows devices without a high precission timer to reduce boot from >100s
|
||||
to <30s.
|
||||
|
||||
Signed-off-by: Álvaro Fernández Rojas <noltari@gmail.com>
|
||||
---
|
||||
drivers/char/hw_random/bcm2835-rng.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/char/hw_random/bcm2835-rng.c
|
||||
+++ b/drivers/char/hw_random/bcm2835-rng.c
|
||||
@@ -163,6 +163,7 @@ static int bcm2835_rng_probe(struct plat
|
||||
priv->rng.init = bcm2835_rng_init;
|
||||
priv->rng.read = bcm2835_rng_read;
|
||||
priv->rng.cleanup = bcm2835_rng_cleanup;
|
||||
+ priv->rng.quality = 1000;
|
||||
|
||||
if (dev_of_node(dev)) {
|
||||
rng_id = of_match_node(bcm2835_rng_of_match, dev->of_node);
|
||||
71
target/linux/generic/pending-5.10/920-mangle_bootargs.patch
Normal file
71
target/linux/generic/pending-5.10/920-mangle_bootargs.patch
Normal file
@@ -0,0 +1,71 @@
|
||||
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(+)
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1790,6 +1790,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
|
||||
--- a/init/main.c
|
||||
+++ b/init/main.c
|
||||
@@ -607,6 +607,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
|
||||
@@ -868,6 +891,7 @@ asmlinkage __visible void __init __no_sa
|
||||
pr_notice("%s", linux_banner);
|
||||
early_security_init();
|
||||
setup_arch(&command_line);
|
||||
+ mangle_bootargs(command_line);
|
||||
setup_boot_config(command_line);
|
||||
setup_command_line(command_line);
|
||||
setup_nr_cpu_ids();
|
||||
Reference in New Issue
Block a user