mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-18 17:33:31 +00:00
sync with upstream patch
This commit is contained in:
parent
331b551c40
commit
a01e7df608
@ -0,0 +1,119 @@
|
||||
From adcc81f148d733b7e8e641300c5590a2cdc13bf3 Mon Sep 17 00:00:00 2001
|
||||
From: Paul Burton <paul.burton@mips.com>
|
||||
Date: Thu, 20 Dec 2018 17:45:43 +0000
|
||||
Subject: MIPS: math-emu: Write-protect delay slot emulation pages
|
||||
|
||||
Mapping the delay slot emulation page as both writeable & executable
|
||||
presents a security risk, in that if an exploit can write to & jump into
|
||||
the page then it can be used as an easy way to execute arbitrary code.
|
||||
|
||||
Prevent this by mapping the page read-only for userland, and using
|
||||
access_process_vm() with the FOLL_FORCE flag to write to it from
|
||||
mips_dsemul().
|
||||
|
||||
This will likely be less efficient due to copy_to_user_page() performing
|
||||
cache maintenance on a whole page, rather than a single line as in the
|
||||
previous use of flush_cache_sigtramp(). However this delay slot
|
||||
emulation code ought not to be running in any performance critical paths
|
||||
anyway so this isn't really a problem, and we can probably do better in
|
||||
copy_to_user_page() anyway in future.
|
||||
|
||||
A major advantage of this approach is that the fix is small & simple to
|
||||
backport to stable kernels.
|
||||
|
||||
Reported-by: Andy Lutomirski <luto@kernel.org>
|
||||
Signed-off-by: Paul Burton <paul.burton@mips.com>
|
||||
Fixes: 432c6bacbd0c ("MIPS: Use per-mm page to execute branch delay slot instructions")
|
||||
Cc: stable@vger.kernel.org # v4.8+
|
||||
Cc: linux-mips@vger.kernel.org
|
||||
Cc: linux-kernel@vger.kernel.org
|
||||
Cc: Rich Felker <dalias@libc.org>
|
||||
Cc: David Daney <david.daney@cavium.com>
|
||||
---
|
||||
arch/mips/kernel/vdso.c | 4 ++--
|
||||
arch/mips/math-emu/dsemul.c | 38 ++++++++++++++++++++------------------
|
||||
2 files changed, 22 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/arch/mips/kernel/vdso.c
|
||||
+++ b/arch/mips/kernel/vdso.c
|
||||
@@ -126,8 +126,8 @@ int arch_setup_additional_pages(struct l
|
||||
|
||||
/* Map delay slot emulation page */
|
||||
base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
|
||||
- VM_READ|VM_WRITE|VM_EXEC|
|
||||
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
|
||||
+ VM_READ | VM_EXEC |
|
||||
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
|
||||
0, NULL);
|
||||
if (IS_ERR_VALUE(base)) {
|
||||
ret = base;
|
||||
--- a/arch/mips/math-emu/dsemul.c
|
||||
+++ b/arch/mips/math-emu/dsemul.c
|
||||
@@ -214,8 +214,9 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
{
|
||||
int isa16 = get_isa16_mode(regs->cp0_epc);
|
||||
mips_instruction break_math;
|
||||
- struct emuframe __user *fr;
|
||||
- int err, fr_idx;
|
||||
+ unsigned long fr_uaddr;
|
||||
+ struct emuframe fr;
|
||||
+ int fr_idx, ret;
|
||||
|
||||
/* NOP is easy */
|
||||
if (ir == 0)
|
||||
@@ -250,27 +251,31 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
fr_idx = alloc_emuframe();
|
||||
if (fr_idx == BD_EMUFRAME_NONE)
|
||||
return SIGBUS;
|
||||
- fr = &dsemul_page()[fr_idx];
|
||||
|
||||
/* Retrieve the appropriately encoded break instruction */
|
||||
break_math = BREAK_MATH(isa16);
|
||||
|
||||
/* Write the instructions to the frame */
|
||||
if (isa16) {
|
||||
- err = __put_user(ir >> 16,
|
||||
- (u16 __user *)(&fr->emul));
|
||||
- err |= __put_user(ir & 0xffff,
|
||||
- (u16 __user *)((long)(&fr->emul) + 2));
|
||||
- err |= __put_user(break_math >> 16,
|
||||
- (u16 __user *)(&fr->badinst));
|
||||
- err |= __put_user(break_math & 0xffff,
|
||||
- (u16 __user *)((long)(&fr->badinst) + 2));
|
||||
+ union mips_instruction _emul = {
|
||||
+ .halfword = { ir >> 16, ir }
|
||||
+ };
|
||||
+ union mips_instruction _badinst = {
|
||||
+ .halfword = { break_math >> 16, break_math }
|
||||
+ };
|
||||
+
|
||||
+ fr.emul = _emul.word;
|
||||
+ fr.badinst = _badinst.word;
|
||||
} else {
|
||||
- err = __put_user(ir, &fr->emul);
|
||||
- err |= __put_user(break_math, &fr->badinst);
|
||||
+ fr.emul = ir;
|
||||
+ fr.badinst = break_math;
|
||||
}
|
||||
|
||||
- if (unlikely(err)) {
|
||||
+ /* Write the frame to user memory */
|
||||
+ fr_uaddr = (unsigned long)&dsemul_page()[fr_idx];
|
||||
+ ret = access_process_vm(current, fr_uaddr, &fr, sizeof(fr),
|
||||
+ FOLL_FORCE | FOLL_WRITE);
|
||||
+ if (unlikely(ret != sizeof(fr))) {
|
||||
MIPS_FPU_EMU_INC_STATS(errors);
|
||||
free_emuframe(fr_idx, current->mm);
|
||||
return SIGBUS;
|
||||
@@ -282,10 +287,7 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
atomic_set(¤t->thread.bd_emu_frame, fr_idx);
|
||||
|
||||
/* Change user register context to execute the frame */
|
||||
- regs->cp0_epc = (unsigned long)&fr->emul | isa16;
|
||||
-
|
||||
- /* Ensure the icache observes our newly written frame */
|
||||
- flush_cache_sigtramp((unsigned long)&fr->emul);
|
||||
+ regs->cp0_epc = fr_uaddr | isa16;
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,79 @@
|
||||
From 03556dab1cb02d85b50d7be3ee3a3bac001f5991 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
Date: Tue, 18 Dec 2018 12:14:06 +0100
|
||||
Subject: [PATCH] arm: cns3xxx: fix writing to wrong PCI registers after
|
||||
alignment
|
||||
|
||||
Originally, cns3xxx used it's own functions for mapping, reading and writing registers.
|
||||
|
||||
Commit 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
removed the internal PCI config write function in favor of the generic one:
|
||||
|
||||
cns3xxx_pci_write_config() --> pci_generic_config_write()
|
||||
|
||||
cns3xxx_pci_write_config() expected aligned addresses, being produced by cns3xxx_pci_map_bus()
|
||||
while the generic one pci_generic_config_write() actually expects the real address
|
||||
as both the function and hardware are capable of byte-aligned writes.
|
||||
|
||||
This currently leads to pci_generic_config_write() writing
|
||||
to the wrong registers on some ocasions.
|
||||
|
||||
First issue seen due to this:
|
||||
|
||||
- driver ath9k gets loaded
|
||||
- The driver wants to write value 0xA8 to register PCI_LATENCY_TIMER, located at 0x0D
|
||||
- cns3xxx_pci_map_bus() aligns the address to 0x0C
|
||||
- pci_generic_config_write() effectively writes 0xA8 into register 0x0C (CACHE_LINE_SIZE)
|
||||
|
||||
This seems to cause some slight instability when certain PCI devices are used.
|
||||
|
||||
Another issue example caused by this this is the PCI bus numbering,
|
||||
where the primary bus is higher than the secondary, which is impossible.
|
||||
|
||||
Before:
|
||||
|
||||
00:00.0 PCI bridge: Cavium, Inc. Device 3400 (rev 01) (prog-if 00 [Normal decode])
|
||||
Flags: bus master, fast devsel, latency 0, IRQ 255
|
||||
Bus: primary=02, secondary=01, subordinate=ff, sec-latency=0
|
||||
|
||||
After fix:
|
||||
|
||||
00:00.0 PCI bridge: Cavium, Inc. Device 3400 (rev 01) (prog-if 00 [Normal decode])
|
||||
Flags: bus master, fast devsel, latency 0, IRQ 255
|
||||
Bus: primary=00, secondary=01, subordinate=02, sec-latency=0
|
||||
|
||||
And very likely some more ..
|
||||
|
||||
Fix all by omitting the alignment being done in the mapping function.
|
||||
|
||||
Fixes: 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
CC: Arnd Bergmann <arnd@arndb.de>
|
||||
CC: Bjorn Helgaas <bhelgaas@google.com>
|
||||
CC: Krzysztof Halasa <khalasa@piap.pl>
|
||||
CC: Olof Johansson <olof@lixom.net>
|
||||
CC: Robin Leblon <robin.leblon@ncentric.com>
|
||||
CC: Rob Herring <robh@kernel.org>
|
||||
CC: Russell King <linux@armlinux.org.uk>
|
||||
CC: Tim Harvey <tharvey@gateworks.com>
|
||||
CC: stable@vger.kernel.org # v4.0+
|
||||
---
|
||||
arch/arm/mach-cns3xxx/pcie.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
|
||||
index 318394ed5c7a..5e11ad3164e0 100644
|
||||
--- a/arch/arm/mach-cns3xxx/pcie.c
|
||||
+++ b/arch/arm/mach-cns3xxx/pcie.c
|
||||
@@ -83,7 +83,7 @@ static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus,
|
||||
} else /* remote PCI bus */
|
||||
base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
|
||||
|
||||
- return base + (where & 0xffc) + (devfn << 12);
|
||||
+ return base + where + (devfn << 12);
|
||||
}
|
||||
|
||||
static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,79 @@
|
||||
From 46bf067870156abd61fe24d14c2486d15b8b502c Mon Sep 17 00:00:00 2001
|
||||
From: Dave Taht <dave@taht.net>
|
||||
Date: Fri, 14 Dec 2018 18:38:40 +0000
|
||||
Subject: [PATCH 1/1] Allow class-e address assignment in ifconfig and early
|
||||
boot
|
||||
|
||||
While the linux kernel became mostly "class-e clean" a decade ago,
|
||||
and most distributions long ago switched to the iproute2 suite
|
||||
of utilities, which allow class-e (240.0.0.0/4) address assignment,
|
||||
distributions relying on busybox, toybox and other forms of
|
||||
ifconfig cannot assign class-e addresses without this kernel patch.
|
||||
|
||||
With this patch, also, a boot command line on these addresses is feasible:
|
||||
(ip=248.0.1.2::248.0.1.1:255.255.255.0).
|
||||
|
||||
While CIDR has been obsolete for 2 decades, and a survey of all the
|
||||
userspace open source code in the world shows most IN_whatever macros
|
||||
are also obsolete... rather than obsolete CIDR from this ioctl entirely,
|
||||
this patch merely enables class-e assignment, sanely.
|
||||
|
||||
H/T to Vince Fuller and his original patch here:
|
||||
https://lkml.org/lkml/2008/1/7/370
|
||||
|
||||
Signed-off-by: Dave Taht <dave.taht@gmail.com>
|
||||
Reviewed-by: John Gilmore <gnu@toad.com>
|
||||
---
|
||||
include/uapi/linux/in.h | 8 ++++++--
|
||||
net/ipv4/devinet.c | 4 +++-
|
||||
net/ipv4/ipconfig.c | 2 ++
|
||||
3 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/uapi/linux/in.h
|
||||
+++ b/include/uapi/linux/in.h
|
||||
@@ -266,8 +266,12 @@ struct sockaddr_in {
|
||||
#define IN_MULTICAST(a) IN_CLASSD(a)
|
||||
#define IN_MULTICAST_NET 0xF0000000
|
||||
|
||||
-#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
|
||||
-#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
|
||||
+#define IN_BADCLASS(a) ((((long int) (a) ) == 0xffffffff)
|
||||
+#define IN_EXPERIMENTAL(a) IN_BADCLASS((a))
|
||||
+
|
||||
+#define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
|
||||
+#define IN_CLASSE_NET 0xffffffff
|
||||
+#define IN_CLASSE_NSHIFT 0
|
||||
|
||||
/* Address to accept any incoming messages. */
|
||||
#define INADDR_ANY ((unsigned long int) 0x00000000)
|
||||
--- a/net/ipv4/devinet.c
|
||||
+++ b/net/ipv4/devinet.c
|
||||
@@ -898,7 +898,7 @@ static int inet_abc_len(__be32 addr)
|
||||
{
|
||||
int rc = -1; /* Something else, probably a multicast. */
|
||||
|
||||
- if (ipv4_is_zeronet(addr))
|
||||
+ if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
|
||||
rc = 0;
|
||||
else {
|
||||
__u32 haddr = ntohl(addr);
|
||||
@@ -909,6 +909,8 @@ static int inet_abc_len(__be32 addr)
|
||||
rc = 16;
|
||||
else if (IN_CLASSC(haddr))
|
||||
rc = 24;
|
||||
+ else if (IN_CLASSE(haddr))
|
||||
+ rc = 32;
|
||||
}
|
||||
|
||||
return rc;
|
||||
--- a/net/ipv4/ipconfig.c
|
||||
+++ b/net/ipv4/ipconfig.c
|
||||
@@ -455,6 +455,8 @@ static int __init ic_defaults(void)
|
||||
ic_netmask = htonl(IN_CLASSB_NET);
|
||||
else if (IN_CLASSC(ntohl(ic_myaddr)))
|
||||
ic_netmask = htonl(IN_CLASSC_NET);
|
||||
+ else if (IN_CLASSE(ntohl(ic_myaddr)))
|
||||
+ ic_netmask = htonl(IN_CLASSE_NET);
|
||||
else {
|
||||
pr_err("IP-Config: Unable to guess netmask for address %pI4\n",
|
||||
&ic_myaddr);
|
@ -0,0 +1,119 @@
|
||||
From adcc81f148d733b7e8e641300c5590a2cdc13bf3 Mon Sep 17 00:00:00 2001
|
||||
From: Paul Burton <paul.burton@mips.com>
|
||||
Date: Thu, 20 Dec 2018 17:45:43 +0000
|
||||
Subject: MIPS: math-emu: Write-protect delay slot emulation pages
|
||||
|
||||
Mapping the delay slot emulation page as both writeable & executable
|
||||
presents a security risk, in that if an exploit can write to & jump into
|
||||
the page then it can be used as an easy way to execute arbitrary code.
|
||||
|
||||
Prevent this by mapping the page read-only for userland, and using
|
||||
access_process_vm() with the FOLL_FORCE flag to write to it from
|
||||
mips_dsemul().
|
||||
|
||||
This will likely be less efficient due to copy_to_user_page() performing
|
||||
cache maintenance on a whole page, rather than a single line as in the
|
||||
previous use of flush_cache_sigtramp(). However this delay slot
|
||||
emulation code ought not to be running in any performance critical paths
|
||||
anyway so this isn't really a problem, and we can probably do better in
|
||||
copy_to_user_page() anyway in future.
|
||||
|
||||
A major advantage of this approach is that the fix is small & simple to
|
||||
backport to stable kernels.
|
||||
|
||||
Reported-by: Andy Lutomirski <luto@kernel.org>
|
||||
Signed-off-by: Paul Burton <paul.burton@mips.com>
|
||||
Fixes: 432c6bacbd0c ("MIPS: Use per-mm page to execute branch delay slot instructions")
|
||||
Cc: stable@vger.kernel.org # v4.8+
|
||||
Cc: linux-mips@vger.kernel.org
|
||||
Cc: linux-kernel@vger.kernel.org
|
||||
Cc: Rich Felker <dalias@libc.org>
|
||||
Cc: David Daney <david.daney@cavium.com>
|
||||
---
|
||||
arch/mips/kernel/vdso.c | 4 ++--
|
||||
arch/mips/math-emu/dsemul.c | 38 ++++++++++++++++++++------------------
|
||||
2 files changed, 22 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/arch/mips/kernel/vdso.c
|
||||
+++ b/arch/mips/kernel/vdso.c
|
||||
@@ -111,8 +111,8 @@ int arch_setup_additional_pages(struct l
|
||||
|
||||
/* Map delay slot emulation page */
|
||||
base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
|
||||
- VM_READ|VM_WRITE|VM_EXEC|
|
||||
- VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
|
||||
+ VM_READ | VM_EXEC |
|
||||
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
|
||||
0);
|
||||
if (IS_ERR_VALUE(base)) {
|
||||
ret = base;
|
||||
--- a/arch/mips/math-emu/dsemul.c
|
||||
+++ b/arch/mips/math-emu/dsemul.c
|
||||
@@ -211,8 +211,9 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
{
|
||||
int isa16 = get_isa16_mode(regs->cp0_epc);
|
||||
mips_instruction break_math;
|
||||
- struct emuframe __user *fr;
|
||||
- int err, fr_idx;
|
||||
+ unsigned long fr_uaddr;
|
||||
+ struct emuframe fr;
|
||||
+ int fr_idx, ret;
|
||||
|
||||
/* NOP is easy */
|
||||
if (ir == 0)
|
||||
@@ -247,27 +248,31 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
fr_idx = alloc_emuframe();
|
||||
if (fr_idx == BD_EMUFRAME_NONE)
|
||||
return SIGBUS;
|
||||
- fr = &dsemul_page()[fr_idx];
|
||||
|
||||
/* Retrieve the appropriately encoded break instruction */
|
||||
break_math = BREAK_MATH(isa16);
|
||||
|
||||
/* Write the instructions to the frame */
|
||||
if (isa16) {
|
||||
- err = __put_user(ir >> 16,
|
||||
- (u16 __user *)(&fr->emul));
|
||||
- err |= __put_user(ir & 0xffff,
|
||||
- (u16 __user *)((long)(&fr->emul) + 2));
|
||||
- err |= __put_user(break_math >> 16,
|
||||
- (u16 __user *)(&fr->badinst));
|
||||
- err |= __put_user(break_math & 0xffff,
|
||||
- (u16 __user *)((long)(&fr->badinst) + 2));
|
||||
+ union mips_instruction _emul = {
|
||||
+ .halfword = { ir >> 16, ir }
|
||||
+ };
|
||||
+ union mips_instruction _badinst = {
|
||||
+ .halfword = { break_math >> 16, break_math }
|
||||
+ };
|
||||
+
|
||||
+ fr.emul = _emul.word;
|
||||
+ fr.badinst = _badinst.word;
|
||||
} else {
|
||||
- err = __put_user(ir, &fr->emul);
|
||||
- err |= __put_user(break_math, &fr->badinst);
|
||||
+ fr.emul = ir;
|
||||
+ fr.badinst = break_math;
|
||||
}
|
||||
|
||||
- if (unlikely(err)) {
|
||||
+ /* Write the frame to user memory */
|
||||
+ fr_uaddr = (unsigned long)&dsemul_page()[fr_idx];
|
||||
+ ret = access_process_vm(current, fr_uaddr, &fr, sizeof(fr),
|
||||
+ FOLL_FORCE | FOLL_WRITE);
|
||||
+ if (unlikely(ret != sizeof(fr))) {
|
||||
MIPS_FPU_EMU_INC_STATS(errors);
|
||||
free_emuframe(fr_idx, current->mm);
|
||||
return SIGBUS;
|
||||
@@ -279,10 +284,7 @@ int mips_dsemul(struct pt_regs *regs, mi
|
||||
atomic_set(¤t->thread.bd_emu_frame, fr_idx);
|
||||
|
||||
/* Change user register context to execute the frame */
|
||||
- regs->cp0_epc = (unsigned long)&fr->emul | isa16;
|
||||
-
|
||||
- /* Ensure the icache observes our newly written frame */
|
||||
- flush_cache_sigtramp((unsigned long)&fr->emul);
|
||||
+ regs->cp0_epc = fr_uaddr | isa16;
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
From 508b09046c0f21678652fb66fd1e9959d55591d2 Mon Sep 17 00:00:00 2001
|
||||
From: Alin Nastac <alin.nastac@gmail.com>
|
||||
Date: Wed, 21 Nov 2018 14:00:30 +0100
|
||||
Subject: [PATCH] netfilter: ipv6: Preserve link scope traffic original oif
|
||||
|
||||
When ip6_route_me_harder is invoked, it resets outgoing interface of:
|
||||
- link-local scoped packets sent by neighbor discovery
|
||||
- multicast packets sent by MLD host
|
||||
- multicast packets send by MLD proxy daemon that sets outgoing
|
||||
interface through IPV6_PKTINFO ipi6_ifindex
|
||||
|
||||
Link-local and multicast packets must keep their original oif after
|
||||
ip6_route_me_harder is called.
|
||||
|
||||
Signed-off-by: Alin Nastac <alin.nastac@gmail.com>
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
net/ipv6/netfilter.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/net/ipv6/netfilter.c
|
||||
+++ b/net/ipv6/netfilter.c
|
||||
@@ -24,7 +24,8 @@ int ip6_route_me_harder(struct net *net,
|
||||
unsigned int hh_len;
|
||||
struct dst_entry *dst;
|
||||
struct flowi6 fl6 = {
|
||||
- .flowi6_oif = skb->sk ? skb->sk->sk_bound_dev_if : 0,
|
||||
+ .flowi6_oif = skb->sk && skb->sk->sk_bound_dev_if ? skb->sk->sk_bound_dev_if :
|
||||
+ rt6_need_strict(&iph->daddr) ? skb_dst(skb)->dev->ifindex : 0,
|
||||
.flowi6_mark = skb->mark,
|
||||
.daddr = iph->daddr,
|
||||
.saddr = iph->saddr,
|
@ -0,0 +1,79 @@
|
||||
From 03556dab1cb02d85b50d7be3ee3a3bac001f5991 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
Date: Tue, 18 Dec 2018 12:14:06 +0100
|
||||
Subject: [PATCH] arm: cns3xxx: fix writing to wrong PCI registers after
|
||||
alignment
|
||||
|
||||
Originally, cns3xxx used it's own functions for mapping, reading and writing registers.
|
||||
|
||||
Commit 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
removed the internal PCI config write function in favor of the generic one:
|
||||
|
||||
cns3xxx_pci_write_config() --> pci_generic_config_write()
|
||||
|
||||
cns3xxx_pci_write_config() expected aligned addresses, being produced by cns3xxx_pci_map_bus()
|
||||
while the generic one pci_generic_config_write() actually expects the real address
|
||||
as both the function and hardware are capable of byte-aligned writes.
|
||||
|
||||
This currently leads to pci_generic_config_write() writing
|
||||
to the wrong registers on some ocasions.
|
||||
|
||||
First issue seen due to this:
|
||||
|
||||
- driver ath9k gets loaded
|
||||
- The driver wants to write value 0xA8 to register PCI_LATENCY_TIMER, located at 0x0D
|
||||
- cns3xxx_pci_map_bus() aligns the address to 0x0C
|
||||
- pci_generic_config_write() effectively writes 0xA8 into register 0x0C (CACHE_LINE_SIZE)
|
||||
|
||||
This seems to cause some slight instability when certain PCI devices are used.
|
||||
|
||||
Another issue example caused by this this is the PCI bus numbering,
|
||||
where the primary bus is higher than the secondary, which is impossible.
|
||||
|
||||
Before:
|
||||
|
||||
00:00.0 PCI bridge: Cavium, Inc. Device 3400 (rev 01) (prog-if 00 [Normal decode])
|
||||
Flags: bus master, fast devsel, latency 0, IRQ 255
|
||||
Bus: primary=02, secondary=01, subordinate=ff, sec-latency=0
|
||||
|
||||
After fix:
|
||||
|
||||
00:00.0 PCI bridge: Cavium, Inc. Device 3400 (rev 01) (prog-if 00 [Normal decode])
|
||||
Flags: bus master, fast devsel, latency 0, IRQ 255
|
||||
Bus: primary=00, secondary=01, subordinate=02, sec-latency=0
|
||||
|
||||
And very likely some more ..
|
||||
|
||||
Fix all by omitting the alignment being done in the mapping function.
|
||||
|
||||
Fixes: 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
CC: Arnd Bergmann <arnd@arndb.de>
|
||||
CC: Bjorn Helgaas <bhelgaas@google.com>
|
||||
CC: Krzysztof Halasa <khalasa@piap.pl>
|
||||
CC: Olof Johansson <olof@lixom.net>
|
||||
CC: Robin Leblon <robin.leblon@ncentric.com>
|
||||
CC: Rob Herring <robh@kernel.org>
|
||||
CC: Russell King <linux@armlinux.org.uk>
|
||||
CC: Tim Harvey <tharvey@gateworks.com>
|
||||
CC: stable@vger.kernel.org # v4.0+
|
||||
---
|
||||
arch/arm/mach-cns3xxx/pcie.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/arch/arm/mach-cns3xxx/pcie.c b/arch/arm/mach-cns3xxx/pcie.c
|
||||
index 318394ed5c7a..5e11ad3164e0 100644
|
||||
--- a/arch/arm/mach-cns3xxx/pcie.c
|
||||
+++ b/arch/arm/mach-cns3xxx/pcie.c
|
||||
@@ -83,7 +83,7 @@ static void __iomem *cns3xxx_pci_map_bus(struct pci_bus *bus,
|
||||
} else /* remote PCI bus */
|
||||
base = cnspci->cfg1_regs + ((busno & 0xf) << 20);
|
||||
|
||||
- return base + (where & 0xffc) + (devfn << 12);
|
||||
+ return base + where + (devfn << 12);
|
||||
}
|
||||
|
||||
static int cns3xxx_pci_read_config(struct pci_bus *bus, unsigned int devfn,
|
||||
--
|
||||
2.17.1
|
||||
|
@ -0,0 +1,588 @@
|
||||
From 06f502f57d0d7728f9fa0f157ec5e4111ddb98f6 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Whitten <ben.whitten@gmail.com>
|
||||
Date: Sun, 10 Dec 2017 21:17:55 +0000
|
||||
Subject: [PATCH] leds: trigger: Introduce a NETDEV trigger
|
||||
|
||||
This commit introduces a NETDEV trigger for named device
|
||||
activity. Available triggers are link, rx, and tx.
|
||||
|
||||
Signed-off-by: Ben Whitten <ben.whitten@gmail.com>
|
||||
Acked-by: Pavel Machek <pavel@ucw.cz>
|
||||
Signed-off-by: Jacek Anaszewski <jacek.anaszewski@gmail.com>
|
||||
---
|
||||
.../ABI/testing/sysfs-class-led-trigger-netdev | 45 ++
|
||||
drivers/leds/trigger/Kconfig | 7 +
|
||||
drivers/leds/trigger/Makefile | 1 +
|
||||
drivers/leds/trigger/ledtrig-netdev.c | 496 +++++++++++++++++++++
|
||||
4 files changed, 549 insertions(+)
|
||||
create mode 100644 Documentation/ABI/testing/sysfs-class-led-trigger-netdev
|
||||
create mode 100644 drivers/leds/trigger/ledtrig-netdev.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/ABI/testing/sysfs-class-led-trigger-netdev
|
||||
@@ -0,0 +1,45 @@
|
||||
+What: /sys/class/leds/<led>/device_name
|
||||
+Date: Dec 2017
|
||||
+KernelVersion: 4.16
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+Description:
|
||||
+ Specifies the network device name to monitor.
|
||||
+
|
||||
+What: /sys/class/leds/<led>/interval
|
||||
+Date: Dec 2017
|
||||
+KernelVersion: 4.16
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+Description:
|
||||
+ Specifies the duration of the LED blink in milliseconds.
|
||||
+ Defaults to 50 ms.
|
||||
+
|
||||
+What: /sys/class/leds/<led>/link
|
||||
+Date: Dec 2017
|
||||
+KernelVersion: 4.16
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+Description:
|
||||
+ Signal the link state of the named network device.
|
||||
+ If set to 0 (default), the LED's normal state is off.
|
||||
+ If set to 1, the LED's normal state reflects the link state
|
||||
+ of the named network device.
|
||||
+ Setting this value also immediately changes the LED state.
|
||||
+
|
||||
+What: /sys/class/leds/<led>/tx
|
||||
+Date: Dec 2017
|
||||
+KernelVersion: 4.16
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+Description:
|
||||
+ Signal transmission of data on the named network device.
|
||||
+ If set to 0 (default), the LED will not blink on transmission.
|
||||
+ If set to 1, the LED will blink for the milliseconds specified
|
||||
+ in interval to signal transmission.
|
||||
+
|
||||
+What: /sys/class/leds/<led>/rx
|
||||
+Date: Dec 2017
|
||||
+KernelVersion: 4.16
|
||||
+Contact: linux-leds@vger.kernel.org
|
||||
+Description:
|
||||
+ Signal reception of data on the named network device.
|
||||
+ If set to 0 (default), the LED will not blink on reception.
|
||||
+ If set to 1, the LED will blink for the milliseconds specified
|
||||
+ in interval to signal reception.
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -126,4 +126,11 @@ config LEDS_TRIGGER_PANIC
|
||||
a different trigger.
|
||||
If unsure, say Y.
|
||||
|
||||
+config LEDS_TRIGGER_NETDEV
|
||||
+ tristate "LED Netdev Trigger"
|
||||
+ depends on NET && LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This allows LEDs to be controlled by network device activity.
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
endif # LEDS_TRIGGERS
|
||||
--- a/drivers/leds/trigger/Makefile
|
||||
+++ b/drivers/leds/trigger/Makefile
|
||||
@@ -10,3 +10,4 @@ obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) +=
|
||||
obj-$(CONFIG_LEDS_TRIGGER_TRANSIENT) += ledtrig-transient.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_CAMERA) += ledtrig-camera.o
|
||||
obj-$(CONFIG_LEDS_TRIGGER_PANIC) += ledtrig-panic.o
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/leds/trigger/ledtrig-netdev.c
|
||||
@@ -0,0 +1,496 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+// Copyright 2017 Ben Whitten <ben.whitten@gmail.com>
|
||||
+// Copyright 2007 Oliver Jowett <oliver@opencloud.com>
|
||||
+//
|
||||
+// LED Kernel Netdev Trigger
|
||||
+//
|
||||
+// Toggles the LED to reflect the link and traffic state of a named net device
|
||||
+//
|
||||
+// Derived from ledtrig-timer.c which is:
|
||||
+// Copyright 2005-2006 Openedhand Ltd.
|
||||
+// Author: Richard Purdie <rpurdie@openedhand.com>
|
||||
+
|
||||
+#include <linux/atomic.h>
|
||||
+#include <linux/ctype.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/jiffies.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/leds.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <linux/spinlock.h>
|
||||
+#include <linux/timer.h>
|
||||
+#include "../leds.h"
|
||||
+
|
||||
+/*
|
||||
+ * Configurable sysfs attributes:
|
||||
+ *
|
||||
+ * device_name - network device name to monitor
|
||||
+ * interval - duration of LED blink, in milliseconds
|
||||
+ * link - LED's normal state reflects whether the link is up
|
||||
+ * (has carrier) or not
|
||||
+ * tx - LED blinks on transmitted data
|
||||
+ * rx - LED blinks on receive data
|
||||
+ *
|
||||
+ */
|
||||
+
|
||||
+struct led_netdev_data {
|
||||
+ spinlock_t lock;
|
||||
+
|
||||
+ struct delayed_work work;
|
||||
+ struct notifier_block notifier;
|
||||
+
|
||||
+ struct led_classdev *led_cdev;
|
||||
+ struct net_device *net_dev;
|
||||
+
|
||||
+ char device_name[IFNAMSIZ];
|
||||
+ atomic_t interval;
|
||||
+ unsigned int last_activity;
|
||||
+
|
||||
+ unsigned long mode;
|
||||
+#define NETDEV_LED_LINK 0
|
||||
+#define NETDEV_LED_TX 1
|
||||
+#define NETDEV_LED_RX 2
|
||||
+#define NETDEV_LED_MODE_LINKUP 3
|
||||
+};
|
||||
+
|
||||
+enum netdev_led_attr {
|
||||
+ NETDEV_ATTR_LINK,
|
||||
+ NETDEV_ATTR_TX,
|
||||
+ NETDEV_ATTR_RX
|
||||
+};
|
||||
+
|
||||
+static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||
+{
|
||||
+ int current_brightness;
|
||||
+ struct led_classdev *led_cdev = trigger_data->led_cdev;
|
||||
+
|
||||
+ current_brightness = led_cdev->brightness;
|
||||
+ if (current_brightness)
|
||||
+ led_cdev->blink_brightness = current_brightness;
|
||||
+ if (!led_cdev->blink_brightness)
|
||||
+ led_cdev->blink_brightness = led_cdev->max_brightness;
|
||||
+
|
||||
+ if (!test_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode))
|
||||
+ led_set_brightness(led_cdev, LED_OFF);
|
||||
+ else {
|
||||
+ if (test_bit(NETDEV_LED_LINK, &trigger_data->mode))
|
||||
+ led_set_brightness(led_cdev,
|
||||
+ led_cdev->blink_brightness);
|
||||
+ else
|
||||
+ led_set_brightness(led_cdev, LED_OFF);
|
||||
+
|
||||
+ /* If we are looking for RX/TX start periodically
|
||||
+ * checking stats
|
||||
+ */
|
||||
+ if (test_bit(NETDEV_LED_TX, &trigger_data->mode) ||
|
||||
+ test_bit(NETDEV_LED_RX, &trigger_data->mode))
|
||||
+ schedule_delayed_work(&trigger_data->work, 0);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_name_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+ ssize_t len;
|
||||
+
|
||||
+ spin_lock_bh(&trigger_data->lock);
|
||||
+ len = sprintf(buf, "%s\n", trigger_data->device_name);
|
||||
+ spin_unlock_bh(&trigger_data->lock);
|
||||
+
|
||||
+ return len;
|
||||
+}
|
||||
+
|
||||
+static ssize_t device_name_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf,
|
||||
+ size_t size)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+
|
||||
+ if (size >= IFNAMSIZ)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
+
|
||||
+ spin_lock_bh(&trigger_data->lock);
|
||||
+
|
||||
+ if (trigger_data->net_dev) {
|
||||
+ dev_put(trigger_data->net_dev);
|
||||
+ trigger_data->net_dev = NULL;
|
||||
+ }
|
||||
+
|
||||
+ strncpy(trigger_data->device_name, buf, size);
|
||||
+ if (size > 0 && trigger_data->device_name[size - 1] == '\n')
|
||||
+ trigger_data->device_name[size - 1] = 0;
|
||||
+
|
||||
+ if (trigger_data->device_name[0] != 0)
|
||||
+ trigger_data->net_dev =
|
||||
+ dev_get_by_name(&init_net, trigger_data->device_name);
|
||||
+
|
||||
+ clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ if (trigger_data->net_dev != NULL)
|
||||
+ if (netif_carrier_ok(trigger_data->net_dev))
|
||||
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+
|
||||
+ trigger_data->last_activity = 0;
|
||||
+
|
||||
+ set_baseline_state(trigger_data);
|
||||
+ spin_unlock_bh(&trigger_data->lock);
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RW(device_name);
|
||||
+
|
||||
+static ssize_t netdev_led_attr_show(struct device *dev, char *buf,
|
||||
+ enum netdev_led_attr attr)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+ int bit;
|
||||
+
|
||||
+ switch (attr) {
|
||||
+ case NETDEV_ATTR_LINK:
|
||||
+ bit = NETDEV_LED_LINK;
|
||||
+ break;
|
||||
+ case NETDEV_ATTR_TX:
|
||||
+ bit = NETDEV_LED_TX;
|
||||
+ break;
|
||||
+ case NETDEV_ATTR_RX:
|
||||
+ bit = NETDEV_LED_RX;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ return sprintf(buf, "%u\n", test_bit(bit, &trigger_data->mode));
|
||||
+}
|
||||
+
|
||||
+static ssize_t netdev_led_attr_store(struct device *dev, const char *buf,
|
||||
+ size_t size, enum netdev_led_attr attr)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+ unsigned long state;
|
||||
+ int ret;
|
||||
+ int bit;
|
||||
+
|
||||
+ ret = kstrtoul(buf, 0, &state);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ switch (attr) {
|
||||
+ case NETDEV_ATTR_LINK:
|
||||
+ bit = NETDEV_LED_LINK;
|
||||
+ break;
|
||||
+ case NETDEV_ATTR_TX:
|
||||
+ bit = NETDEV_LED_TX;
|
||||
+ break;
|
||||
+ case NETDEV_ATTR_RX:
|
||||
+ bit = NETDEV_LED_RX;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
+
|
||||
+ if (state)
|
||||
+ set_bit(bit, &trigger_data->mode);
|
||||
+ else
|
||||
+ clear_bit(bit, &trigger_data->mode);
|
||||
+
|
||||
+ set_baseline_state(trigger_data);
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static ssize_t link_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ return netdev_led_attr_show(dev, buf, NETDEV_ATTR_LINK);
|
||||
+}
|
||||
+
|
||||
+static ssize_t link_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf, size_t size)
|
||||
+{
|
||||
+ return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_LINK);
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RW(link);
|
||||
+
|
||||
+static ssize_t tx_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ return netdev_led_attr_show(dev, buf, NETDEV_ATTR_TX);
|
||||
+}
|
||||
+
|
||||
+static ssize_t tx_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf, size_t size)
|
||||
+{
|
||||
+ return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_TX);
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RW(tx);
|
||||
+
|
||||
+static ssize_t rx_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ return netdev_led_attr_show(dev, buf, NETDEV_ATTR_RX);
|
||||
+}
|
||||
+
|
||||
+static ssize_t rx_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf, size_t size)
|
||||
+{
|
||||
+ return netdev_led_attr_store(dev, buf, size, NETDEV_ATTR_RX);
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RW(rx);
|
||||
+
|
||||
+static ssize_t interval_show(struct device *dev,
|
||||
+ struct device_attribute *attr, char *buf)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+
|
||||
+ return sprintf(buf, "%u\n",
|
||||
+ jiffies_to_msecs(atomic_read(&trigger_data->interval)));
|
||||
+}
|
||||
+
|
||||
+static ssize_t interval_store(struct device *dev,
|
||||
+ struct device_attribute *attr, const char *buf,
|
||||
+ size_t size)
|
||||
+{
|
||||
+ struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+ unsigned long value;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = kstrtoul(buf, 0, &value);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* impose some basic bounds on the timer interval */
|
||||
+ if (value >= 5 && value <= 10000) {
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
+
|
||||
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(value));
|
||||
+ set_baseline_state(trigger_data); /* resets timer */
|
||||
+ }
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static DEVICE_ATTR_RW(interval);
|
||||
+
|
||||
+static int netdev_trig_notify(struct notifier_block *nb,
|
||||
+ unsigned long evt, void *dv)
|
||||
+{
|
||||
+ struct net_device *dev =
|
||||
+ netdev_notifier_info_to_dev((struct netdev_notifier_info *)dv);
|
||||
+ struct led_netdev_data *trigger_data = container_of(nb,
|
||||
+ struct
|
||||
+ led_netdev_data,
|
||||
+ notifier);
|
||||
+
|
||||
+ if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE
|
||||
+ && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER
|
||||
+ && evt != NETDEV_CHANGENAME)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ if (strcmp(dev->name, trigger_data->device_name))
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
+
|
||||
+ spin_lock_bh(&trigger_data->lock);
|
||||
+
|
||||
+ clear_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ switch (evt) {
|
||||
+ case NETDEV_REGISTER:
|
||||
+ if (trigger_data->net_dev)
|
||||
+ dev_put(trigger_data->net_dev);
|
||||
+ dev_hold(dev);
|
||||
+ trigger_data->net_dev = dev;
|
||||
+ break;
|
||||
+ case NETDEV_CHANGENAME:
|
||||
+ case NETDEV_UNREGISTER:
|
||||
+ if (trigger_data->net_dev) {
|
||||
+ dev_put(trigger_data->net_dev);
|
||||
+ trigger_data->net_dev = NULL;
|
||||
+ }
|
||||
+ break;
|
||||
+ case NETDEV_UP:
|
||||
+ case NETDEV_CHANGE:
|
||||
+ if (netif_carrier_ok(dev))
|
||||
+ set_bit(NETDEV_LED_MODE_LINKUP, &trigger_data->mode);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ set_baseline_state(trigger_data);
|
||||
+
|
||||
+ spin_unlock_bh(&trigger_data->lock);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+/* here's the real work! */
|
||||
+static void netdev_trig_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct led_netdev_data *trigger_data = container_of(work,
|
||||
+ struct
|
||||
+ led_netdev_data,
|
||||
+ work.work);
|
||||
+ struct rtnl_link_stats64 *dev_stats;
|
||||
+ unsigned int new_activity;
|
||||
+ struct rtnl_link_stats64 temp;
|
||||
+ unsigned long interval;
|
||||
+ int invert;
|
||||
+
|
||||
+ /* If we dont have a device, insure we are off */
|
||||
+ if (!trigger_data->net_dev) {
|
||||
+ led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* If we are not looking for RX/TX then return */
|
||||
+ if (!test_bit(NETDEV_LED_TX, &trigger_data->mode) &&
|
||||
+ !test_bit(NETDEV_LED_RX, &trigger_data->mode))
|
||||
+ return;
|
||||
+
|
||||
+ dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
|
||||
+ new_activity =
|
||||
+ (test_bit(NETDEV_LED_TX, &trigger_data->mode) ?
|
||||
+ dev_stats->tx_packets : 0) +
|
||||
+ (test_bit(NETDEV_LED_RX, &trigger_data->mode) ?
|
||||
+ dev_stats->rx_packets : 0);
|
||||
+
|
||||
+ if (trigger_data->last_activity != new_activity) {
|
||||
+ led_stop_software_blink(trigger_data->led_cdev);
|
||||
+
|
||||
+ invert = test_bit(NETDEV_LED_LINK, &trigger_data->mode);
|
||||
+ interval = jiffies_to_msecs(
|
||||
+ atomic_read(&trigger_data->interval));
|
||||
+ /* base state is ON (link present) */
|
||||
+ led_blink_set_oneshot(trigger_data->led_cdev,
|
||||
+ &interval,
|
||||
+ &interval,
|
||||
+ invert);
|
||||
+ trigger_data->last_activity = new_activity;
|
||||
+ }
|
||||
+
|
||||
+ schedule_delayed_work(&trigger_data->work,
|
||||
+ (atomic_read(&trigger_data->interval)*2));
|
||||
+}
|
||||
+
|
||||
+static void netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct led_netdev_data *trigger_data;
|
||||
+ int rc;
|
||||
+
|
||||
+ trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||
+ if (!trigger_data)
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_init(&trigger_data->lock);
|
||||
+
|
||||
+ trigger_data->notifier.notifier_call = netdev_trig_notify;
|
||||
+ trigger_data->notifier.priority = 10;
|
||||
+
|
||||
+ INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
|
||||
+
|
||||
+ trigger_data->led_cdev = led_cdev;
|
||||
+ trigger_data->net_dev = NULL;
|
||||
+ trigger_data->device_name[0] = 0;
|
||||
+
|
||||
+ trigger_data->mode = 0;
|
||||
+ atomic_set(&trigger_data->interval, msecs_to_jiffies(50));
|
||||
+ trigger_data->last_activity = 0;
|
||||
+
|
||||
+ led_cdev->trigger_data = trigger_data;
|
||||
+
|
||||
+ rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
|
||||
+ if (rc)
|
||||
+ goto err_out;
|
||||
+ rc = device_create_file(led_cdev->dev, &dev_attr_link);
|
||||
+ if (rc)
|
||||
+ goto err_out_device_name;
|
||||
+ rc = device_create_file(led_cdev->dev, &dev_attr_rx);
|
||||
+ if (rc)
|
||||
+ goto err_out_link;
|
||||
+ rc = device_create_file(led_cdev->dev, &dev_attr_tx);
|
||||
+ if (rc)
|
||||
+ goto err_out_rx;
|
||||
+ rc = device_create_file(led_cdev->dev, &dev_attr_interval);
|
||||
+ if (rc)
|
||||
+ goto err_out_tx;
|
||||
+ rc = register_netdevice_notifier(&trigger_data->notifier);
|
||||
+ if (rc)
|
||||
+ goto err_out_interval;
|
||||
+ return;
|
||||
+
|
||||
+err_out_interval:
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||
+err_out_tx:
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||
+err_out_rx:
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||
+err_out_link:
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||
+err_out_device_name:
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
+err_out:
|
||||
+ led_cdev->trigger_data = NULL;
|
||||
+ kfree(trigger_data);
|
||||
+}
|
||||
+
|
||||
+static void netdev_trig_deactivate(struct led_classdev *led_cdev)
|
||||
+{
|
||||
+ struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
+
|
||||
+ if (trigger_data) {
|
||||
+ unregister_netdevice_notifier(&trigger_data->notifier);
|
||||
+
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_link);
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_rx);
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_tx);
|
||||
+ device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||
+
|
||||
+ cancel_delayed_work_sync(&trigger_data->work);
|
||||
+
|
||||
+ if (trigger_data->net_dev)
|
||||
+ dev_put(trigger_data->net_dev);
|
||||
+
|
||||
+ kfree(trigger_data);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static struct led_trigger netdev_led_trigger = {
|
||||
+ .name = "netdev",
|
||||
+ .activate = netdev_trig_activate,
|
||||
+ .deactivate = netdev_trig_deactivate,
|
||||
+};
|
||||
+
|
||||
+static int __init netdev_trig_init(void)
|
||||
+{
|
||||
+ return led_trigger_register(&netdev_led_trigger);
|
||||
+}
|
||||
+
|
||||
+static void __exit netdev_trig_exit(void)
|
||||
+{
|
||||
+ led_trigger_unregister(&netdev_led_trigger);
|
||||
+}
|
||||
+
|
||||
+module_init(netdev_trig_init);
|
||||
+module_exit(netdev_trig_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Ben Whitten <ben.whitten@gmail.com>");
|
||||
+MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
|
||||
+MODULE_DESCRIPTION("Netdev LED trigger");
|
||||
+MODULE_LICENSE("GPL v2");
|
@ -0,0 +1,44 @@
|
||||
From a74515604a7b171f2702bdcbd1e231225fb456d0 Mon Sep 17 00:00:00 2001
|
||||
From: Anderson Luiz Alves <alacn1@gmail.com>
|
||||
Date: Fri, 30 Nov 2018 21:58:36 -0200
|
||||
Subject: [PATCH] mv88e6060: disable hardware level MAC learning
|
||||
|
||||
Disable hardware level MAC learning because it breaks station roaming.
|
||||
When enabled it drops all frames that arrive from a MAC address
|
||||
that is on a different port at learning table.
|
||||
|
||||
Signed-off-by: Anderson Luiz Alves <alacn1@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/mv88e6060.c | 10 +++-------
|
||||
1 file changed, 3 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/dsa/mv88e6060.c
|
||||
+++ b/drivers/net/dsa/mv88e6060.c
|
||||
@@ -114,8 +114,7 @@ static int mv88e6060_switch_reset(struct
|
||||
/* Reset the switch. */
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
|
||||
GLOBAL_ATU_CONTROL_SWRESET |
|
||||
- GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
|
||||
- GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
|
||||
+ GLOBAL_ATU_CONTROL_LEARNDIS);
|
||||
|
||||
/* Wait up to one second for reset to complete. */
|
||||
timeout = jiffies + 1 * HZ;
|
||||
@@ -140,13 +139,10 @@ static int mv88e6060_setup_global(struct
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_CONTROL, GLOBAL_CONTROL_MAX_FRAME_1536);
|
||||
|
||||
- /* Enable automatic address learning, set the address
|
||||
- * database size to 1024 entries, and set the default aging
|
||||
- * time to 5 minutes.
|
||||
+ /* Disable automatic address learning.
|
||||
*/
|
||||
REG_WRITE(REG_GLOBAL, GLOBAL_ATU_CONTROL,
|
||||
- GLOBAL_ATU_CONTROL_ATUSIZE_1024 |
|
||||
- GLOBAL_ATU_CONTROL_ATE_AGE_5MIN);
|
||||
+ GLOBAL_ATU_CONTROL_LEARNDIS);
|
||||
|
||||
return 0;
|
||||
}
|
@ -273,6 +273,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
|
||||
# CONFIG_ARCH_ZYNQMP is not set
|
||||
# CONFIG_ARCNET is not set
|
||||
# CONFIG_ARC_EMAC is not set
|
||||
# CONFIG_ARM64_ERRATUM_1024718 is not set
|
||||
# CONFIG_ARM64_ERRATUM_819472 is not set
|
||||
# CONFIG_ARM64_ERRATUM_824069 is not set
|
||||
# CONFIG_ARM64_ERRATUM_826319 is not set
|
||||
@ -282,7 +283,6 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
|
||||
# CONFIG_ARM64_ERRATUM_843419 is not set
|
||||
# CONFIG_ARM64_ERRATUM_845719 is not set
|
||||
# CONFIG_ARM64_ERRATUM_858921 is not set
|
||||
# CONFIG_ARM64_ERRATUM_1024718 is not set
|
||||
# CONFIG_ARM64_RELOC_TEST is not set
|
||||
# CONFIG_ARM_APPENDED_DTB is not set
|
||||
# CONFIG_ARM_ARCH_TIMER is not set
|
||||
@ -627,7 +627,7 @@ CONFIG_BRIDGE=y
|
||||
CONFIG_BRIDGE_IGMP_SNOOPING=y
|
||||
# CONFIG_BRIDGE_NETFILTER is not set
|
||||
# CONFIG_BRIDGE_NF_EBTABLES is not set
|
||||
# CONFIG_BRIDGE_VLAN_FILTERING is not set
|
||||
CONFIG_BRIDGE_VLAN_FILTERING=y
|
||||
# CONFIG_BROADCOM_PHY is not set
|
||||
CONFIG_BROKEN_ON_SMP=y
|
||||
# CONFIG_BSD_DISKLABEL is not set
|
||||
@ -717,6 +717,8 @@ CONFIG_CARDBUS=y
|
||||
# CONFIG_CB710_CORE is not set
|
||||
# CONFIG_CC10001_ADC is not set
|
||||
# CONFIG_CCS811 is not set
|
||||
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
# CONFIG_CC_STACKPROTECTOR is not set
|
||||
CONFIG_CC_STACKPROTECTOR_NONE=y
|
||||
# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
|
||||
@ -916,9 +918,9 @@ CONFIG_CRYPTO_BLKCIPHER2=y
|
||||
# CONFIG_CRYPTO_DEV_QAT_DH895xCC is not set
|
||||
# CONFIG_CRYPTO_DEV_QAT_DH895xCCVF is not set
|
||||
# CONFIG_CRYPTO_DEV_QCE is not set
|
||||
# CONFIG_CRYPTO_DEV_S5P is not set
|
||||
# CONFIG_CRYPTO_DEV_SAFEXCEL is not set
|
||||
# CONFIG_CRYPTO_DEV_SAHARA is not set
|
||||
# CONFIG_CRYPTO_DEV_S5P is not set
|
||||
# CONFIG_CRYPTO_DEV_TALITOS is not set
|
||||
# CONFIG_CRYPTO_DEV_VIRTIO is not set
|
||||
# CONFIG_CRYPTO_DH is not set
|
||||
@ -1180,12 +1182,14 @@ CONFIG_DQL=y
|
||||
# CONFIG_DRM_NOUVEAU is not set
|
||||
# CONFIG_DRM_NXP_PTN3460 is not set
|
||||
# CONFIG_DRM_OMAP is not set
|
||||
# CONFIG_DRM_PANEL_INNOLUX_P079ZCA is not set
|
||||
# CONFIG_DRM_PANEL_JDI_LT070ME05000 is not set
|
||||
# CONFIG_DRM_PANEL_LG_LG4573 is not set
|
||||
# CONFIG_DRM_PANEL_LVDS is not set
|
||||
# CONFIG_DRM_PANEL_PANASONIC_VVX10F034N00 is not set
|
||||
# CONFIG_DRM_PANEL_RASPBERRYPI_TOUCHSCREEN is not set
|
||||
# CONFIG_DRM_PANEL_SAMSUNG_LD9040 is not set
|
||||
# CONFIG_DRM_PANEL_SAMSUNG_S6E3HA2 is not set
|
||||
# CONFIG_DRM_PANEL_SAMSUNG_S6E8AA0 is not set
|
||||
# CONFIG_DRM_PANEL_SHARP_LQ101R1SX01 is not set
|
||||
# CONFIG_DRM_PANEL_SHARP_LS043T1LE01 is not set
|
||||
@ -3162,13 +3166,13 @@ CONFIG_NFS_V3=y
|
||||
# CONFIG_NFT_DUP_IPV6 is not set
|
||||
# CONFIG_NFT_FIB_IPV4 is not set
|
||||
# CONFIG_NFT_FIB_IPV6 is not set
|
||||
# CONFIG_NFT_FIB_NETDEV is not set
|
||||
# CONFIG_NFT_FLOW_OFFLOAD is not set
|
||||
# CONFIG_NFT_OBJREF is not set
|
||||
# CONFIG_NFT_RT is not set
|
||||
# CONFIG_NFT_SET_BITMAP is not set
|
||||
# CONFIG_NF_CONNTRACK is not set
|
||||
# CONFIG_NF_CONNTRACK_AMANDA is not set
|
||||
# CONFIG_NF_CONNTRACK_CHAIN_EVENTS is not set
|
||||
# CONFIG_NF_CONNTRACK_EVENTS is not set
|
||||
# CONFIG_NF_CONNTRACK_FTP is not set
|
||||
# CONFIG_NF_CONNTRACK_H323 is not set
|
||||
@ -4496,6 +4500,7 @@ CONFIG_SND_PROC_FS=y
|
||||
# CONFIG_SND_SOC_FSL_SPDIF is not set
|
||||
# CONFIG_SND_SOC_FSL_SSI is not set
|
||||
# CONFIG_SND_SOC_GTM601 is not set
|
||||
# CONFIG_SND_SOC_ICS43432 is not set
|
||||
# CONFIG_SND_SOC_IMG is not set
|
||||
# CONFIG_SND_SOC_IMX_AUDMUX is not set
|
||||
# CONFIG_SND_SOC_IMX_ES8328 is not set
|
||||
|
@ -743,12 +743,11 @@ CONFIG_CARDBUS=y
|
||||
# CONFIG_CB710_CORE is not set
|
||||
# CONFIG_CC10001_ADC is not set
|
||||
# CONFIG_CCS811 is not set
|
||||
CONFIG_CC_HAS_SANCOV_TRACE_PC=y
|
||||
CONFIG_CC_HAS_STACKPROTECTOR_NONE=y
|
||||
CONFIG_CC_IS_GCC=y
|
||||
CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE=y
|
||||
# CONFIG_CC_OPTIMIZE_FOR_SIZE is not set
|
||||
# CONFIG_CC_STACKPROTECTOR is not set
|
||||
CONFIG_CC_STACKPROTECTOR_NONE=y
|
||||
# CONFIG_CC_STACKPROTECTOR_REGULAR is not set
|
||||
# CONFIG_CC_STACKPROTECTOR_STRONG is not set
|
||||
# CONFIG_CDROM_PKTCDVD is not set
|
||||
# CONFIG_CEPH_FS is not set
|
||||
# CONFIG_CEPH_LIB is not set
|
||||
@ -802,6 +801,7 @@ CONFIG_CIFS_STATS=y
|
||||
# CONFIG_CIFS_WEAK_PW_HASH is not set
|
||||
# CONFIG_CIFS_XATTR is not set
|
||||
# CONFIG_CIO_DAC is not set
|
||||
CONFIG_CLANG_VERSION=0
|
||||
# CONFIG_CLEANCACHE is not set
|
||||
# CONFIG_CLKSRC_VERSATILE is not set
|
||||
# CONFIG_CLK_HSDK is not set
|
||||
@ -1102,6 +1102,7 @@ CONFIG_DEBUG_KERNEL=y
|
||||
# CONFIG_DEBUG_PREEMPT is not set
|
||||
# CONFIG_DEBUG_RODATA is not set
|
||||
# CONFIG_DEBUG_RODATA_TEST is not set
|
||||
# CONFIG_DEBUG_RSEQ is not set
|
||||
# CONFIG_DEBUG_RT_MUTEXES is not set
|
||||
# CONFIG_DEBUG_RWSEMS is not set
|
||||
# CONFIG_DEBUG_SECTION_MISMATCH is not set
|
||||
@ -1531,6 +1532,7 @@ CONFIG_GACT_PROB=y
|
||||
# CONFIG_GAMEPORT is not set
|
||||
# CONFIG_GATEWORKS_GW16083 is not set
|
||||
# CONFIG_GCC_PLUGINS is not set
|
||||
CONFIG_GCC_VERSION=70400
|
||||
# CONFIG_GCOV is not set
|
||||
# CONFIG_GCOV_KERNEL is not set
|
||||
# CONFIG_GDB_SCRIPTS is not set
|
||||
@ -1650,6 +1652,7 @@ CONFIG_HAVE_KERNEL_XZ=y
|
||||
CONFIG_HAVE_KPROBES=y
|
||||
CONFIG_HAVE_KRETPROBES=y
|
||||
CONFIG_HAVE_NMI=y
|
||||
CONFIG_HAVE_STACKPROTECTOR=y
|
||||
# CONFIG_HCALL_STATS is not set
|
||||
# CONFIG_HDC100X is not set
|
||||
# CONFIG_HDLC is not set
|
||||
@ -3350,6 +3353,7 @@ CONFIG_NF_CONNTRACK_PROCFS=y
|
||||
# CONFIG_NF_DUP_IPV6 is not set
|
||||
# CONFIG_NF_FLOW_TABLE is not set
|
||||
# CONFIG_NF_LOG_ARP is not set
|
||||
# CONFIG_NF_LOG_BRIDGE is not set
|
||||
# CONFIG_NF_LOG_IPV4 is not set
|
||||
# CONFIG_NF_LOG_NETDEV is not set
|
||||
# CONFIG_NF_NAT is not set
|
||||
@ -3661,7 +3665,10 @@ CONFIG_PCI_SYSCALL=y
|
||||
# CONFIG_PHY_PXA_28NM_HSIC is not set
|
||||
# CONFIG_PHY_PXA_28NM_USB2 is not set
|
||||
# CONFIG_PHY_QCOM_DWC3 is not set
|
||||
# CONFIG_PHY_QCOM_USB_HS is not set
|
||||
# CONFIG_PHY_QCOM_USB_HSIC is not set
|
||||
# CONFIG_PHY_SAMSUNG_USB2 is not set
|
||||
# CONFIG_PHY_TUSB1210 is not set
|
||||
# CONFIG_PHY_XGENE is not set
|
||||
# CONFIG_PI433 is not set
|
||||
# CONFIG_PID_IN_CONTEXTIDR is not set
|
||||
@ -3685,6 +3692,7 @@ CONFIG_PINMUX=y
|
||||
# CONFIG_PLATFORM_MHU is not set
|
||||
# CONFIG_PLAT_SPEAR is not set
|
||||
# CONFIG_PLIP is not set
|
||||
CONFIG_PLUGIN_HOSTCC=""
|
||||
# CONFIG_PLX_HERMES is not set
|
||||
# CONFIG_PM is not set
|
||||
# CONFIG_PMBUS is not set
|
||||
@ -4939,6 +4947,7 @@ CONFIG_SSB_POSSIBLE=y
|
||||
# CONFIG_SSB_SILENT is not set
|
||||
# CONFIG_SSFDC is not set
|
||||
# CONFIG_STACKPROTECTOR is not set
|
||||
# CONFIG_STACKPROTECTOR_STRONG is not set
|
||||
# CONFIG_STACKTRACE is not set
|
||||
CONFIG_STACKTRACE_SUPPORT=y
|
||||
# CONFIG_STACK_TRACER is not set
|
||||
@ -5326,6 +5335,7 @@ CONFIG_USB_DEFAULT_PERSIST=y
|
||||
# CONFIG_USB_DWC3_OF_SIMPLE is not set
|
||||
# CONFIG_USB_DWC3_PCI is not set
|
||||
# CONFIG_USB_DWC3_QCOM is not set
|
||||
# CONFIG_USB_DWC3_ULPI is not set
|
||||
# CONFIG_USB_DYNAMIC_MINORS is not set
|
||||
# CONFIG_USB_EG20T is not set
|
||||
# CONFIG_USB_EHCI_ATH79 is not set
|
||||
|
@ -260,6 +260,7 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
|
||||
# CONFIG_ARCH_ZYNQMP is not set
|
||||
# CONFIG_ARCNET is not set
|
||||
# CONFIG_ARC_EMAC is not set
|
||||
# CONFIG_ARM64_ERRATUM_1024718 is not set
|
||||
# CONFIG_ARM64_ERRATUM_819472 is not set
|
||||
# CONFIG_ARM64_ERRATUM_824069 is not set
|
||||
# CONFIG_ARM64_ERRATUM_826319 is not set
|
||||
@ -268,7 +269,6 @@ CONFIG_ARCH_MMAP_RND_COMPAT_BITS_MIN=8
|
||||
# CONFIG_ARM64_ERRATUM_834220 is not set
|
||||
# CONFIG_ARM64_ERRATUM_843419 is not set
|
||||
# CONFIG_ARM64_ERRATUM_845719 is not set
|
||||
# CONFIG_ARM64_ERRATUM_1024718 is not set
|
||||
# CONFIG_ARM_APPENDED_DTB is not set
|
||||
# CONFIG_ARM_ARCH_TIMER is not set
|
||||
# CONFIG_ARM_BIG_LITTLE_CPUFREQ is not set
|
||||
@ -598,7 +598,7 @@ CONFIG_BRIDGE=y
|
||||
CONFIG_BRIDGE_IGMP_SNOOPING=y
|
||||
# CONFIG_BRIDGE_NETFILTER is not set
|
||||
# CONFIG_BRIDGE_NF_EBTABLES is not set
|
||||
# CONFIG_BRIDGE_VLAN_FILTERING is not set
|
||||
CONFIG_BRIDGE_VLAN_FILTERING=y
|
||||
# CONFIG_BROADCOM_PHY is not set
|
||||
CONFIG_BROKEN_ON_SMP=y
|
||||
# CONFIG_BSD_DISKLABEL is not set
|
||||
@ -691,8 +691,8 @@ CONFIG_CC_STACKPROTECTOR_NONE=y
|
||||
# CONFIG_CFG80211_CERTIFICATION_ONUS is not set
|
||||
# CONFIG_CGROUPS is not set
|
||||
# CONFIG_CGROUP_DEBUG is not set
|
||||
# CONFIG_CGROUP_NET_PRIO is not set
|
||||
# CONFIG_CGROUP_NET_CLASSID is not set
|
||||
# CONFIG_CGROUP_NET_PRIO is not set
|
||||
# CONFIG_CHARGER_BQ2415X is not set
|
||||
# CONFIG_CHARGER_BQ24190 is not set
|
||||
# CONFIG_CHARGER_BQ24257 is not set
|
||||
@ -2974,7 +2974,6 @@ CONFIG_NFS_V3=y
|
||||
# CONFIG_NFT_DUP_IPV6 is not set
|
||||
# CONFIG_NF_CONNTRACK is not set
|
||||
# CONFIG_NF_CONNTRACK_AMANDA is not set
|
||||
# CONFIG_NF_CONNTRACK_CHAIN_EVENTS is not set
|
||||
# CONFIG_NF_CONNTRACK_EVENTS is not set
|
||||
# CONFIG_NF_CONNTRACK_FTP is not set
|
||||
# CONFIG_NF_CONNTRACK_H323 is not set
|
||||
@ -4225,6 +4224,7 @@ CONFIG_SND_PROC_FS=y
|
||||
# CONFIG_SND_SOC_FSL_SPDIF is not set
|
||||
# CONFIG_SND_SOC_FSL_SSI is not set
|
||||
# CONFIG_SND_SOC_GTM601 is not set
|
||||
# CONFIG_SND_SOC_ICS43432 is not set
|
||||
# CONFIG_SND_SOC_IMG is not set
|
||||
# CONFIG_SND_SOC_IMX_AUDMUX is not set
|
||||
# CONFIG_SND_SOC_IMX_ES8328 is not set
|
||||
|
@ -1,444 +0,0 @@
|
||||
/*
|
||||
* LED Kernel Netdev Trigger
|
||||
*
|
||||
* Toggles the LED to reflect the link and traffic state of a named net device
|
||||
*
|
||||
* Copyright 2007 Oliver Jowett <oliver@opencloud.com>
|
||||
*
|
||||
* Derived from ledtrig-timer.c which is:
|
||||
* Copyright 2005-2006 Openedhand Ltd.
|
||||
* Author: Richard Purdie <rpurdie@openedhand.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/module.h>
|
||||
#include <linux/jiffies.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/leds.h>
|
||||
|
||||
#include "leds.h"
|
||||
|
||||
/*
|
||||
* Configurable sysfs attributes:
|
||||
*
|
||||
* device_name - network device name to monitor
|
||||
*
|
||||
* interval - duration of LED blink, in milliseconds
|
||||
*
|
||||
* mode - either "none" (LED is off) or a space separated list of one or more of:
|
||||
* link: LED's normal state reflects whether the link is up (has carrier) or not
|
||||
* tx: LED blinks on transmitted data
|
||||
* rx: LED blinks on receive data
|
||||
*
|
||||
* Some suggestions:
|
||||
*
|
||||
* Simple link status LED:
|
||||
* $ echo netdev >someled/trigger
|
||||
* $ echo eth0 >someled/device_name
|
||||
* $ echo link >someled/mode
|
||||
*
|
||||
* Ethernet-style link/activity LED:
|
||||
* $ echo netdev >someled/trigger
|
||||
* $ echo eth0 >someled/device_name
|
||||
* $ echo "link tx rx" >someled/mode
|
||||
*
|
||||
* Modem-style tx/rx LEDs:
|
||||
* $ echo netdev >led1/trigger
|
||||
* $ echo ppp0 >led1/device_name
|
||||
* $ echo tx >led1/mode
|
||||
* $ echo netdev >led2/trigger
|
||||
* $ echo ppp0 >led2/device_name
|
||||
* $ echo rx >led2/mode
|
||||
*
|
||||
*/
|
||||
|
||||
#define MODE_LINK 1
|
||||
#define MODE_TX 2
|
||||
#define MODE_RX 4
|
||||
|
||||
struct led_netdev_data {
|
||||
spinlock_t lock;
|
||||
|
||||
struct delayed_work work;
|
||||
struct notifier_block notifier;
|
||||
|
||||
struct led_classdev *led_cdev;
|
||||
struct net_device *net_dev;
|
||||
|
||||
char device_name[IFNAMSIZ];
|
||||
unsigned interval;
|
||||
unsigned mode;
|
||||
unsigned link_up;
|
||||
unsigned last_activity;
|
||||
};
|
||||
|
||||
static void set_baseline_state(struct led_netdev_data *trigger_data)
|
||||
{
|
||||
if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
|
||||
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||
else
|
||||
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||
|
||||
if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
|
||||
schedule_delayed_work(&trigger_data->work, trigger_data->interval);
|
||||
}
|
||||
|
||||
static ssize_t led_device_name_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
sprintf(buf, "%s\n", trigger_data->device_name);
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
static ssize_t led_device_name_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
|
||||
if (size >= IFNAMSIZ)
|
||||
return -EINVAL;
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
||||
strcpy(trigger_data->device_name, buf);
|
||||
if (size > 0 && trigger_data->device_name[size-1] == '\n')
|
||||
trigger_data->device_name[size-1] = 0;
|
||||
trigger_data->link_up = 0;
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
if (trigger_data->device_name[0] != 0) {
|
||||
/* check for existing device to update from */
|
||||
trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name);
|
||||
if (trigger_data->net_dev != NULL)
|
||||
trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
|
||||
}
|
||||
|
||||
set_baseline_state(trigger_data);
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
|
||||
|
||||
static ssize_t led_mode_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
||||
if (trigger_data->mode == 0) {
|
||||
strcpy(buf, "none\n");
|
||||
} else {
|
||||
if (trigger_data->mode & MODE_LINK)
|
||||
strcat(buf, "link ");
|
||||
if (trigger_data->mode & MODE_TX)
|
||||
strcat(buf, "tx ");
|
||||
if (trigger_data->mode & MODE_RX)
|
||||
strcat(buf, "rx ");
|
||||
strcat(buf, "\n");
|
||||
}
|
||||
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
return strlen(buf)+1;
|
||||
}
|
||||
|
||||
static ssize_t led_mode_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
char copybuf[128];
|
||||
int new_mode = -1;
|
||||
char *p, *token;
|
||||
|
||||
/* take a copy since we don't want to trash the inbound buffer when using strsep */
|
||||
strncpy(copybuf, buf, sizeof(copybuf));
|
||||
copybuf[sizeof(copybuf) - 1] = 0;
|
||||
p = copybuf;
|
||||
|
||||
while ((token = strsep(&p, " \t\n")) != NULL) {
|
||||
if (!*token)
|
||||
continue;
|
||||
|
||||
if (new_mode == -1)
|
||||
new_mode = 0;
|
||||
|
||||
if (!strcmp(token, "none"))
|
||||
new_mode = 0;
|
||||
else if (!strcmp(token, "tx"))
|
||||
new_mode |= MODE_TX;
|
||||
else if (!strcmp(token, "rx"))
|
||||
new_mode |= MODE_RX;
|
||||
else if (!strcmp(token, "link"))
|
||||
new_mode |= MODE_LINK;
|
||||
else
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (new_mode == -1)
|
||||
return -EINVAL;
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
trigger_data->mode = new_mode;
|
||||
set_baseline_state(trigger_data);
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
|
||||
|
||||
static ssize_t led_interval_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
return strlen(buf) + 1;
|
||||
}
|
||||
|
||||
static ssize_t led_interval_store(struct device *dev,
|
||||
struct device_attribute *attr, const char *buf, size_t size)
|
||||
{
|
||||
struct led_classdev *led_cdev = dev_get_drvdata(dev);
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
int ret = -EINVAL;
|
||||
char *after;
|
||||
unsigned long value = simple_strtoul(buf, &after, 10);
|
||||
size_t count = after - buf;
|
||||
|
||||
if (isspace(*after))
|
||||
count++;
|
||||
|
||||
/* impose some basic bounds on the timer interval */
|
||||
if (count == size && value >= 5 && value <= 10000) {
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
trigger_data->interval = msecs_to_jiffies(value);
|
||||
set_baseline_state(trigger_data); /* resets timer */
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
ret = count;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
|
||||
|
||||
static int netdev_trig_notify(struct notifier_block *nb,
|
||||
unsigned long evt,
|
||||
void *dv)
|
||||
{
|
||||
struct net_device *dev = netdev_notifier_info_to_dev((struct netdev_notifier_info *) dv);
|
||||
struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
|
||||
|
||||
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER && evt != NETDEV_CHANGENAME)
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (strcmp(dev->name, trigger_data->device_name))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
||||
if (evt == NETDEV_REGISTER || evt == NETDEV_CHANGENAME) {
|
||||
if (trigger_data->net_dev != NULL)
|
||||
dev_put(trigger_data->net_dev);
|
||||
|
||||
dev_hold(dev);
|
||||
trigger_data->net_dev = dev;
|
||||
trigger_data->link_up = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
|
||||
dev_put(trigger_data->net_dev);
|
||||
trigger_data->net_dev = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* UP / DOWN / CHANGE */
|
||||
|
||||
trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
|
||||
set_baseline_state(trigger_data);
|
||||
|
||||
done:
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
|
||||
/* here's the real work! */
|
||||
static void netdev_trig_work(struct work_struct *work)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = container_of(work, struct led_netdev_data, work.work);
|
||||
struct rtnl_link_stats64 *dev_stats;
|
||||
unsigned new_activity;
|
||||
struct rtnl_link_stats64 temp;
|
||||
|
||||
if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
|
||||
/* we don't need to do timer work, just reflect link state. */
|
||||
led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
|
||||
return;
|
||||
}
|
||||
|
||||
dev_stats = dev_get_stats(trigger_data->net_dev, &temp);
|
||||
new_activity =
|
||||
((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
|
||||
((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
|
||||
|
||||
if (trigger_data->mode & MODE_LINK) {
|
||||
/* base state is ON (link present) */
|
||||
/* if there's no link, we don't get this far and the LED is off */
|
||||
|
||||
/* OFF -> ON always */
|
||||
/* ON -> OFF on activity */
|
||||
if (trigger_data->led_cdev->brightness == LED_OFF) {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||
} else if (trigger_data->last_activity != new_activity) {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||
}
|
||||
} else {
|
||||
/* base state is OFF */
|
||||
/* ON -> OFF always */
|
||||
/* OFF -> ON on activity */
|
||||
if (trigger_data->led_cdev->brightness == LED_FULL) {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_OFF);
|
||||
} else if (trigger_data->last_activity != new_activity) {
|
||||
led_set_brightness(trigger_data->led_cdev, LED_FULL);
|
||||
}
|
||||
}
|
||||
|
||||
trigger_data->last_activity = new_activity;
|
||||
schedule_delayed_work(&trigger_data->work, trigger_data->interval);
|
||||
}
|
||||
|
||||
static void netdev_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_netdev_data *trigger_data;
|
||||
int rc;
|
||||
|
||||
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
|
||||
if (!trigger_data)
|
||||
return;
|
||||
|
||||
spin_lock_init(&trigger_data->lock);
|
||||
|
||||
trigger_data->notifier.notifier_call = netdev_trig_notify;
|
||||
trigger_data->notifier.priority = 10;
|
||||
|
||||
INIT_DELAYED_WORK(&trigger_data->work, netdev_trig_work);
|
||||
|
||||
trigger_data->led_cdev = led_cdev;
|
||||
trigger_data->net_dev = NULL;
|
||||
trigger_data->device_name[0] = 0;
|
||||
|
||||
trigger_data->mode = 0;
|
||||
trigger_data->interval = msecs_to_jiffies(50);
|
||||
trigger_data->link_up = 0;
|
||||
trigger_data->last_activity = 0;
|
||||
|
||||
led_cdev->trigger_data = trigger_data;
|
||||
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
|
||||
if (rc)
|
||||
goto err_out;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_mode);
|
||||
if (rc)
|
||||
goto err_out_device_name;
|
||||
rc = device_create_file(led_cdev->dev, &dev_attr_interval);
|
||||
if (rc)
|
||||
goto err_out_mode;
|
||||
|
||||
register_netdevice_notifier(&trigger_data->notifier);
|
||||
return;
|
||||
|
||||
err_out_mode:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_mode);
|
||||
err_out_device_name:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
err_out:
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(trigger_data);
|
||||
}
|
||||
|
||||
static void netdev_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
|
||||
|
||||
if (trigger_data) {
|
||||
unregister_netdevice_notifier(&trigger_data->notifier);
|
||||
|
||||
device_remove_file(led_cdev->dev, &dev_attr_device_name);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_mode);
|
||||
device_remove_file(led_cdev->dev, &dev_attr_interval);
|
||||
|
||||
cancel_delayed_work_sync(&trigger_data->work);
|
||||
|
||||
spin_lock_bh(&trigger_data->lock);
|
||||
|
||||
if (trigger_data->net_dev) {
|
||||
dev_put(trigger_data->net_dev);
|
||||
trigger_data->net_dev = NULL;
|
||||
}
|
||||
|
||||
spin_unlock_bh(&trigger_data->lock);
|
||||
|
||||
kfree(trigger_data);
|
||||
}
|
||||
}
|
||||
|
||||
static struct led_trigger netdev_led_trigger = {
|
||||
.name = "netdev",
|
||||
.activate = netdev_trig_activate,
|
||||
.deactivate = netdev_trig_deactivate,
|
||||
};
|
||||
|
||||
static int __init netdev_trig_init(void)
|
||||
{
|
||||
return led_trigger_register(&netdev_led_trigger);
|
||||
}
|
||||
|
||||
static void __exit netdev_trig_exit(void)
|
||||
{
|
||||
led_trigger_unregister(&netdev_led_trigger);
|
||||
}
|
||||
|
||||
module_init(netdev_trig_init);
|
||||
module_exit(netdev_trig_exit);
|
||||
|
||||
MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
|
||||
MODULE_DESCRIPTION("Netdev LED trigger");
|
||||
MODULE_LICENSE("GPL");
|
@ -79,9 +79,15 @@ static int mtdsplit_parse_eva(struct mtd_info *master,
|
||||
return EVA_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_eva_of_match_table[] = {
|
||||
{ .compatible = "avm,eva-firmware" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct mtd_part_parser mtdsplit_eva_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "eva-fw",
|
||||
.of_match_table = mtdsplit_eva_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_eva,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -120,9 +120,15 @@ mtdsplit_fit_parse(struct mtd_info *mtd,
|
||||
return 2;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_fit_of_match_table[] = {
|
||||
{ .compatible = "denx,fit" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct mtd_part_parser uimage_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "fit-fw",
|
||||
.of_match_table = mtdsplit_fit_of_match_table,
|
||||
.parse_fn = mtdsplit_fit_parse,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -256,9 +256,15 @@ mtdsplit_jimage_parse_generic(struct mtd_info *master,
|
||||
jimage_verify_default);
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_jimage_of_match_table[] = {
|
||||
{ .compatible = "amit,jimage" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct mtd_part_parser jimage_generic_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "jimage-fw",
|
||||
.of_match_table = mtdsplit_jimage_of_match_table,
|
||||
.parse_fn = mtdsplit_jimage_parse_generic,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -79,9 +79,16 @@ static int mtdsplit_parse_lzma(struct mtd_info *master,
|
||||
return LZMA_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_lzma_of_match_table[] = {
|
||||
{ .compatible = "lzma" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtdsplit_lzma_of_match_table);
|
||||
|
||||
static struct mtd_part_parser mtdsplit_lzma_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "lzma-fw",
|
||||
.of_match_table = mtdsplit_lzma_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_lzma,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -100,9 +100,16 @@ static int mtdsplit_parse_minor(struct mtd_info *master,
|
||||
return MINOR_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_minor_of_match_table[] = {
|
||||
{ .compatible = "mikrotik,minor" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtdsplit_minor_of_match_table);
|
||||
|
||||
static struct mtd_part_parser mtdsplit_minor_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "minor-fw",
|
||||
.of_match_table = mtdsplit_minor_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_minor,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -93,9 +93,16 @@ static int mtdsplit_parse_seama(struct mtd_info *master,
|
||||
return SEAMA_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_seama_of_match_table[] = {
|
||||
{ .compatible = "seama" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtdsplit_seama_of_match_table);
|
||||
|
||||
static struct mtd_part_parser mtdsplit_seama_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "seama-fw",
|
||||
.of_match_table = mtdsplit_seama_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_seama,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -152,9 +152,15 @@ static int mtdsplit_parse_tplink(struct mtd_info *master,
|
||||
return TPLINK_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_tplink_of_match_table[] = {
|
||||
{ .compatible = "tplink,firmware" },
|
||||
{},
|
||||
};
|
||||
|
||||
static struct mtd_part_parser mtdsplit_tplink_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "tplink-fw",
|
||||
.of_match_table = mtdsplit_tplink_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_tplink,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -130,9 +130,16 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static const struct of_device_id trx_parser_of_match_table[] = {
|
||||
{ .compatible = "openwrt,trx" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, trx_parser_of_match_table);
|
||||
|
||||
static struct mtd_part_parser trx_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "trx-fw",
|
||||
.of_match_table = trx_parser_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_trx,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/mtd/mtd.h>
|
||||
#include <linux/mtd/partitions.h>
|
||||
#include <linux/version.h>
|
||||
#include <linux/byteorder/generic.h>
|
||||
|
||||
#include "mtdsplit.h"
|
||||
@ -239,9 +240,19 @@ mtdsplit_uimage_parse_generic(struct mtd_info *master,
|
||||
uimage_verify_default);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||
static const struct of_device_id mtdsplit_uimage_of_match_table[] = {
|
||||
{ .compatible = "denx,uimage" },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct mtd_part_parser uimage_generic_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "uimage-fw",
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||
.of_match_table = mtdsplit_uimage_of_match_table,
|
||||
#endif
|
||||
.parse_fn = mtdsplit_uimage_parse_generic,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
@ -296,9 +307,19 @@ mtdsplit_uimage_parse_netgear(struct mtd_info *master,
|
||||
uimage_verify_wndr3700);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||
static const struct of_device_id mtdsplit_uimage_netgear_of_match_table[] = {
|
||||
{ .compatible = "netgear,uimage" },
|
||||
{},
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct mtd_part_parser uimage_netgear_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "netgear-fw",
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 9, 0)
|
||||
.of_match_table = mtdsplit_uimage_netgear_of_match_table,
|
||||
#endif
|
||||
.parse_fn = mtdsplit_uimage_parse_netgear,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -107,9 +107,16 @@ static int mtdsplit_parse_wrgg(struct mtd_info *master,
|
||||
return WRGG_NR_PARTS;
|
||||
}
|
||||
|
||||
static const struct of_device_id mtdsplit_wrgg_of_match_table[] = {
|
||||
{ .compatible = "wrg" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, mtdsplit_wrgg_of_match_table);
|
||||
|
||||
static struct mtd_part_parser mtdsplit_wrgg_parser = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "wrgg-fw",
|
||||
.of_match_table = mtdsplit_wrgg_of_match_table,
|
||||
.parse_fn = mtdsplit_parse_wrgg,
|
||||
.type = MTD_PARSER_TYPE_FIRMWARE,
|
||||
};
|
||||
|
@ -295,6 +295,17 @@ ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val)
|
||||
|
||||
return ret;
|
||||
}
|
||||
void
|
||||
ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
|
||||
u16 dbg_addr, u16 *dbg_data)
|
||||
{
|
||||
struct mii_bus *bus = priv->mii_bus;
|
||||
|
||||
mutex_lock(&bus->mdio_lock);
|
||||
bus->write(bus, phy_addr, MII_ATH_DBG_ADDR, dbg_addr);
|
||||
*dbg_data = bus->read(bus, phy_addr, MII_ATH_DBG_DATA);
|
||||
mutex_unlock(&bus->mdio_lock);
|
||||
}
|
||||
|
||||
void
|
||||
ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
|
||||
@ -749,7 +760,6 @@ static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
|
||||
u16 r2, page;
|
||||
u16 r1_func0, r1_func1, r1_func2;
|
||||
u32 t, val0, val1, val2;
|
||||
int i;
|
||||
|
||||
split_addr(AR8216_REG_ATU_FUNC0, &r1_func0, &r2, &page);
|
||||
r2 |= 0x10;
|
||||
@ -785,12 +795,7 @@ static void ar8216_get_arl_entry(struct ar8xxx_priv *priv,
|
||||
if (!*status)
|
||||
break;
|
||||
|
||||
i = 0;
|
||||
t = AR8216_ATU_PORT0;
|
||||
while (!(val2 & t) && ++i < priv->dev.ports)
|
||||
t <<= 1;
|
||||
|
||||
a->port = i;
|
||||
a->portmap = (val2 & AR8216_ATU_PORTS) >> AR8216_ATU_PORTS_S;
|
||||
a->mac[0] = (val0 & AR8216_ATU_ADDR5) >> AR8216_ATU_ADDR5_S;
|
||||
a->mac[1] = (val0 & AR8216_ATU_ADDR4) >> AR8216_ATU_ADDR4_S;
|
||||
a->mac[2] = (val1 & AR8216_ATU_ADDR3) >> AR8216_ATU_ADDR3_S;
|
||||
@ -1516,8 +1521,12 @@ ar8xxx_sw_get_arl_table(struct switch_dev *dev,
|
||||
*/
|
||||
for (j = 0; j < i; ++j) {
|
||||
a1 = &priv->arl_table[j];
|
||||
if (a->port == a1->port && !memcmp(a->mac, a1->mac, sizeof(a->mac)))
|
||||
goto duplicate;
|
||||
if (!memcmp(a->mac, a1->mac, sizeof(a->mac))) {
|
||||
/* ignore ports already seen in former entry */
|
||||
a->portmap &= ~a1->portmap;
|
||||
if (!a->portmap)
|
||||
goto duplicate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1534,7 +1543,7 @@ ar8xxx_sw_get_arl_table(struct switch_dev *dev,
|
||||
for (j = 0; j < priv->dev.ports; ++j) {
|
||||
for (k = 0; k < i; ++k) {
|
||||
a = &priv->arl_table[k];
|
||||
if (a->port != j)
|
||||
if (!(a->portmap & BIT(j)))
|
||||
continue;
|
||||
len += snprintf(buf + len, sizeof(priv->arl_buf) - len,
|
||||
"Port %d: MAC %02x:%02x:%02x:%02x:%02x:%02x\n",
|
||||
@ -2104,7 +2113,8 @@ ar8xxx_phy_read_status(struct phy_device *phydev)
|
||||
|
||||
phydev->state = PHY_RUNNING;
|
||||
netif_carrier_on(phydev->attached_dev);
|
||||
phydev->adjust_link(phydev->attached_dev);
|
||||
if (phydev->adjust_link)
|
||||
phydev->adjust_link(phydev->attached_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -2167,7 +2177,7 @@ ar8xxx_phy_probe(struct phy_device *phydev)
|
||||
int ret;
|
||||
|
||||
/* skip PHYs at unused adresses */
|
||||
if (phydev->mdio.addr != 0 && phydev->mdio.addr != 4)
|
||||
if (phydev->mdio.addr != 0 && phydev->mdio.addr != 3 && phydev->mdio.addr != 4)
|
||||
return -ENODEV;
|
||||
|
||||
if (!ar8xxx_is_possible(phydev->mdio.bus))
|
||||
@ -2226,6 +2236,8 @@ found:
|
||||
phydev->supported |= SUPPORTED_1000baseT_Full;
|
||||
phydev->advertising |= ADVERTISED_1000baseT_Full;
|
||||
}
|
||||
if (priv->chip->phy_rgmii_set)
|
||||
priv->chip->phy_rgmii_set(priv, phydev);
|
||||
}
|
||||
|
||||
phydev->priv = priv;
|
||||
|
@ -112,6 +112,7 @@
|
||||
|
||||
#define AR8216_REG_ATU_FUNC2 0x0058
|
||||
#define AR8216_ATU_PORTS BITS(0, 6)
|
||||
#define AR8216_ATU_PORTS_S 0
|
||||
#define AR8216_ATU_PORT0 BIT(0)
|
||||
#define AR8216_ATU_PORT1 BIT(1)
|
||||
#define AR8216_ATU_PORT2 BIT(2)
|
||||
@ -367,7 +368,7 @@ enum arl_op {
|
||||
};
|
||||
|
||||
struct arl_entry {
|
||||
u8 port;
|
||||
u16 portmap;
|
||||
u8 mac[6];
|
||||
};
|
||||
|
||||
@ -412,6 +413,7 @@ struct ar8xxx_chip {
|
||||
void (*get_arl_entry)(struct ar8xxx_priv *priv, struct arl_entry *a,
|
||||
u32 *status, enum arl_op op);
|
||||
int (*sw_hw_apply)(struct switch_dev *dev);
|
||||
void (*phy_rgmii_set)(struct ar8xxx_priv *priv, struct phy_device *phydev);
|
||||
|
||||
const struct ar8xxx_mib_desc *mib_decs;
|
||||
unsigned num_mibs;
|
||||
@ -476,6 +478,9 @@ ar8xxx_write(struct ar8xxx_priv *priv, int reg, u32 val);
|
||||
u32
|
||||
ar8xxx_rmw(struct ar8xxx_priv *priv, int reg, u32 mask, u32 val);
|
||||
|
||||
void
|
||||
ar8xxx_phy_dbg_read(struct ar8xxx_priv *priv, int phy_addr,
|
||||
u16 dbg_addr, u16 *dbg_data);
|
||||
void
|
||||
ar8xxx_phy_dbg_write(struct ar8xxx_priv *priv, int phy_addr,
|
||||
u16 dbg_addr, u16 dbg_data);
|
||||
|
@ -127,6 +127,49 @@ ar8327_get_pad_cfg(struct ar8327_pad_cfg *cfg)
|
||||
return t;
|
||||
}
|
||||
|
||||
static void
|
||||
ar8327_phy_rgmii_set(struct ar8xxx_priv *priv, struct phy_device *phydev)
|
||||
{
|
||||
u16 phy_val = 0;
|
||||
int phyaddr = phydev->mdio.addr;
|
||||
struct device_node *np = phydev->mdio.dev.of_node;
|
||||
|
||||
if (!np)
|
||||
return;
|
||||
|
||||
if (!of_property_read_bool(np, "qca,phy-rgmii-en")) {
|
||||
pr_err("ar8327: qca,phy-rgmii-en is not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ar8xxx_phy_dbg_read(priv, phyaddr,
|
||||
AR8327_PHY_MODE_SEL, &phy_val);
|
||||
phy_val |= AR8327_PHY_MODE_SEL_RGMII;
|
||||
ar8xxx_phy_dbg_write(priv, phyaddr,
|
||||
AR8327_PHY_MODE_SEL, phy_val);
|
||||
|
||||
/* set rgmii tx clock delay if needed */
|
||||
if (!of_property_read_bool(np, "qca,txclk-delay-en")) {
|
||||
pr_err("ar8327: qca,txclk-delay-en is not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ar8xxx_phy_dbg_read(priv, phyaddr,
|
||||
AR8327_PHY_SYS_CTRL, &phy_val);
|
||||
phy_val |= AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY;
|
||||
ar8xxx_phy_dbg_write(priv, phyaddr,
|
||||
AR8327_PHY_SYS_CTRL, phy_val);
|
||||
|
||||
/* set rgmii rx clock delay if needed */
|
||||
if (!of_property_read_bool(np, "qca,rxclk-delay-en")) {
|
||||
pr_err("ar8327: qca,rxclk-delay-en is not specified\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
ar8xxx_phy_dbg_read(priv, phyaddr,
|
||||
AR8327_PHY_TEST_CTRL, &phy_val);
|
||||
phy_val |= AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY;
|
||||
ar8xxx_phy_dbg_write(priv, phyaddr,
|
||||
AR8327_PHY_TEST_CTRL, phy_val);
|
||||
}
|
||||
|
||||
static void
|
||||
ar8327_phy_fixup(struct ar8xxx_priv *priv, int phy)
|
||||
{
|
||||
@ -1057,8 +1100,7 @@ static void ar8327_get_arl_entry(struct ar8xxx_priv *priv,
|
||||
struct mii_bus *bus = priv->mii_bus;
|
||||
u16 r2, page;
|
||||
u16 r1_data0, r1_data1, r1_data2, r1_func;
|
||||
u32 t, val0, val1, val2;
|
||||
int i;
|
||||
u32 val0, val1, val2;
|
||||
|
||||
split_addr(AR8327_REG_ATU_DATA0, &r1_data0, &r2, &page);
|
||||
r2 |= 0x10;
|
||||
@ -1095,12 +1137,7 @@ static void ar8327_get_arl_entry(struct ar8xxx_priv *priv,
|
||||
if (!*status)
|
||||
break;
|
||||
|
||||
i = 0;
|
||||
t = AR8327_ATU_PORT0;
|
||||
while (!(val1 & t) && ++i < AR8327_NUM_PORTS)
|
||||
t <<= 1;
|
||||
|
||||
a->port = i;
|
||||
a->portmap = (val1 & AR8327_ATU_PORTS) >> AR8327_ATU_PORTS_S;
|
||||
a->mac[0] = (val0 & AR8327_ATU_ADDR0) >> AR8327_ATU_ADDR0_S;
|
||||
a->mac[1] = (val0 & AR8327_ATU_ADDR1) >> AR8327_ATU_ADDR1_S;
|
||||
a->mac[2] = (val0 & AR8327_ATU_ADDR2) >> AR8327_ATU_ADDR2_S;
|
||||
@ -1496,6 +1533,7 @@ const struct ar8xxx_chip ar8337_chip = {
|
||||
.set_mirror_regs = ar8327_set_mirror_regs,
|
||||
.get_arl_entry = ar8327_get_arl_entry,
|
||||
.sw_hw_apply = ar8327_sw_hw_apply,
|
||||
.phy_rgmii_set = ar8327_phy_rgmii_set,
|
||||
|
||||
.num_mibs = ARRAY_SIZE(ar8236_mibs),
|
||||
.mib_decs = ar8236_mibs,
|
||||
|
@ -199,6 +199,7 @@
|
||||
#define AR8327_ATU_ADDR5 BITS(8, 8)
|
||||
#define AR8327_ATU_ADDR5_S 8
|
||||
#define AR8327_ATU_PORTS BITS(16, 7)
|
||||
#define AR8327_ATU_PORTS_S 16
|
||||
#define AR8327_ATU_PORT0 BIT(16)
|
||||
#define AR8327_ATU_PORT1 BIT(17)
|
||||
#define AR8327_ATU_PORT2 BIT(18)
|
||||
@ -283,6 +284,13 @@
|
||||
|
||||
#define AR8337_PAD_MAC06_EXCHANGE_EN BIT(31)
|
||||
|
||||
#define AR8327_PHY_MODE_SEL 0x12
|
||||
#define AR8327_PHY_MODE_SEL_RGMII BIT(3)
|
||||
#define AR8327_PHY_TEST_CTRL 0x0
|
||||
#define AR8327_PHY_TEST_CTRL_RGMII_RX_DELAY BIT(15)
|
||||
#define AR8327_PHY_SYS_CTRL 0x5
|
||||
#define AR8327_PHY_SYS_CTRL_RGMII_TX_DELAY BIT(8)
|
||||
|
||||
enum ar8327_led_pattern {
|
||||
AR8327_LED_PATTERN_OFF = 0,
|
||||
AR8327_LED_PATTERN_BLINK,
|
||||
|
@ -273,47 +273,34 @@ static struct b53_io_ops b53_mdio_ops = {
|
||||
|
||||
static int b53_phy_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device dev;
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
/* allow the generic phy driver to take over */
|
||||
if (phydev->mdio.addr != B53_PSEUDO_PHY && phydev->mdio.addr != 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev.current_page = 0xff;
|
||||
dev.priv = phydev->mdio.bus;
|
||||
dev.ops = &b53_mdio_ops;
|
||||
dev.pdata = NULL;
|
||||
mutex_init(&dev.reg_mutex);
|
||||
dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
ret = b53_switch_detect(&dev);
|
||||
dev->current_page = 0xff;
|
||||
dev->priv = phydev->mdio.bus;
|
||||
dev->ops = &b53_mdio_ops;
|
||||
dev->pdata = NULL;
|
||||
mutex_init(&dev->reg_mutex);
|
||||
|
||||
ret = b53_switch_detect(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (is5325(&dev) || is5365(&dev))
|
||||
if (is5325(dev) || is5365(dev))
|
||||
phydev->supported = SUPPORTED_100baseT_Full;
|
||||
else
|
||||
phydev->supported = SUPPORTED_1000baseT_Full;
|
||||
|
||||
phydev->advertising = phydev->supported;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *dev;
|
||||
int ret;
|
||||
|
||||
dev = b53_switch_alloc(&phydev->mdio.dev, &b53_mdio_ops, phydev->mdio.bus);
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
|
||||
/* we don't use page 0xff, so force a page set */
|
||||
dev->current_page = 0xff;
|
||||
/* force the ethX as alias */
|
||||
dev->sw_dev.alias = phydev->attached_dev->name;
|
||||
|
||||
ret = b53_switch_register(dev);
|
||||
if (ret) {
|
||||
dev_err(dev->dev, "failed to register switch: %i\n", ret);
|
||||
@ -325,6 +312,18 @@ static int b53_phy_config_init(struct phy_device *phydev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int b53_phy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *dev = phydev->priv;
|
||||
|
||||
/* we don't use page 0xff, so force a page set */
|
||||
dev->current_page = 0xff;
|
||||
/* force the ethX as alias */
|
||||
dev->sw_dev.alias = phydev->attached_dev->name;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void b53_phy_remove(struct phy_device *phydev)
|
||||
{
|
||||
struct b53_device *priv = phydev->priv;
|
||||
|
@ -454,6 +454,86 @@ static int mvsw61xx_set_enable_vlan(struct switch_dev *dev,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_get_mirror_rx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
val->value.i = state->mirror_rx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_set_mirror_rx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
state->mirror_rx = val->value.i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_get_mirror_tx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
val->value.i = state->mirror_tx;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_set_mirror_tx_enable(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
state->mirror_tx = val->value.i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_get_mirror_monitor_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
val->value.i = state->monitor_port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_set_mirror_monitor_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
state->monitor_port = val->value.i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_get_mirror_source_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
val->value.i = state->source_port;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_set_mirror_source_port(struct switch_dev *dev,
|
||||
const struct switch_attr *attr, struct switch_val *val)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
|
||||
state->source_port = val->value.i;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mvsw61xx_vtu_program(struct switch_dev *dev)
|
||||
{
|
||||
struct mvsw61xx_state *state = get_state(dev);
|
||||
@ -604,6 +684,40 @@ static int mvsw61xx_update_state(struct switch_dev *dev)
|
||||
|
||||
mvsw61xx_vtu_program(dev);
|
||||
|
||||
/* port mirroring */
|
||||
/* reset all mirror registers */
|
||||
for (i = 0; i < dev->ports; i++) {
|
||||
reg = sr16(dev, MV_PORTREG(CONTROL2, i));
|
||||
reg &= ~(MV_MIRROR_RX_SRC_MASK | MV_MIRROR_TX_SRC_MASK);
|
||||
sw16(dev, MV_PORTREG(CONTROL2, i), reg);
|
||||
}
|
||||
reg = sr16(dev, MV_GLOBALREG(MONITOR_CTRL));
|
||||
reg |= MV_MIRROR_RX_DEST_MASK | MV_MIRROR_TX_DEST_MASK;
|
||||
sw16(dev, MV_GLOBALREG(MONITOR_CTRL), reg);
|
||||
|
||||
/* now enable mirroring if necessary */
|
||||
if (state->mirror_rx) {
|
||||
/* set ingress monitor source */
|
||||
reg = sr16(dev, MV_PORTREG(CONTROL2, state->source_port)) & ~MV_MIRROR_RX_SRC_MASK;
|
||||
reg |= state->mirror_rx << MV_MIRROR_RX_SRC_SHIFT;
|
||||
sw16(dev, MV_PORTREG(CONTROL2, state->source_port), reg);
|
||||
/* set ingress monitor destination */
|
||||
reg = sr16(dev, MV_GLOBALREG(MONITOR_CTRL)) & ~MV_MIRROR_RX_DEST_MASK;
|
||||
reg |= state->monitor_port << MV_MIRROR_RX_DEST_SHIFT;
|
||||
sw16(dev, MV_GLOBALREG(MONITOR_CTRL), reg);
|
||||
}
|
||||
|
||||
if (state->mirror_tx) {
|
||||
/* set egress monitor source */
|
||||
reg = sr16(dev, MV_PORTREG(CONTROL2, state->source_port)) & ~MV_MIRROR_TX_SRC_MASK;
|
||||
reg |= state->mirror_tx << MV_MIRROR_TX_SRC_SHIFT;
|
||||
sw16(dev, MV_PORTREG(CONTROL2, state->source_port), reg);
|
||||
/* set egress monitor destination */
|
||||
reg = sr16(dev, MV_GLOBALREG(MONITOR_CTRL)) & ~MV_MIRROR_TX_DEST_MASK;
|
||||
reg |= state->monitor_port << MV_MIRROR_TX_DEST_SHIFT;
|
||||
sw16(dev, MV_GLOBALREG(MONITOR_CTRL), reg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -693,6 +807,11 @@ static int _mvsw61xx_reset(struct switch_dev *dev, bool full)
|
||||
|
||||
state->vlan_enabled = 0;
|
||||
|
||||
state->mirror_rx = false;
|
||||
state->mirror_tx = false;
|
||||
state->source_port = 0;
|
||||
state->monitor_port = 0;
|
||||
|
||||
mvsw61xx_update_state(dev);
|
||||
|
||||
/* Re-enable ports */
|
||||
@ -710,10 +829,6 @@ static int mvsw61xx_reset(struct switch_dev *dev)
|
||||
return _mvsw61xx_reset(dev, false);
|
||||
}
|
||||
|
||||
enum {
|
||||
MVSW61XX_ENABLE_VLAN,
|
||||
};
|
||||
|
||||
enum {
|
||||
MVSW61XX_VLAN_PORT_BASED,
|
||||
MVSW61XX_VLAN_ID,
|
||||
@ -725,14 +840,45 @@ enum {
|
||||
};
|
||||
|
||||
static const struct switch_attr mvsw61xx_global[] = {
|
||||
[MVSW61XX_ENABLE_VLAN] = {
|
||||
.id = MVSW61XX_ENABLE_VLAN,
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "enable_vlan",
|
||||
.description = "Enable 802.1q VLAN support",
|
||||
.get = mvsw61xx_get_enable_vlan,
|
||||
.set = mvsw61xx_set_enable_vlan,
|
||||
},
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "enable_mirror_rx",
|
||||
.description = "Enable mirroring of RX packets",
|
||||
.set = mvsw61xx_set_mirror_rx_enable,
|
||||
.get = mvsw61xx_get_mirror_rx_enable,
|
||||
.max = 1
|
||||
},
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "enable_mirror_tx",
|
||||
.description = "Enable mirroring of TX packets",
|
||||
.set = mvsw61xx_set_mirror_tx_enable,
|
||||
.get = mvsw61xx_get_mirror_tx_enable,
|
||||
.max = 1
|
||||
},
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "mirror_monitor_port",
|
||||
.description = "Mirror monitor port",
|
||||
.set = mvsw61xx_set_mirror_monitor_port,
|
||||
.get = mvsw61xx_get_mirror_monitor_port,
|
||||
.max = MV_PORTS - 1
|
||||
},
|
||||
{
|
||||
.type = SWITCH_TYPE_INT,
|
||||
.name = "mirror_source_port",
|
||||
.description = "Mirror source port",
|
||||
.set = mvsw61xx_set_mirror_source_port,
|
||||
.get = mvsw61xx_get_mirror_source_port,
|
||||
.max = MV_PORTS - 1
|
||||
},
|
||||
};
|
||||
|
||||
static const struct switch_attr mvsw61xx_vlan[] = {
|
||||
|
@ -165,6 +165,7 @@ enum {
|
||||
MV_GLOBAL_VTU_DATA1 = 0x07,
|
||||
MV_GLOBAL_VTU_DATA2 = 0x08,
|
||||
MV_GLOBAL_VTU_DATA3 = 0x09,
|
||||
MV_GLOBAL_MONITOR_CTRL = 0x1a,
|
||||
MV_GLOBAL_CONTROL2 = 0x1c,
|
||||
};
|
||||
#define MV_GLOBALREG(_type) MV_SWITCH_GLOBAL, MV_GLOBAL_##_type
|
||||
@ -242,6 +243,16 @@ enum {
|
||||
#define MV_FDB_HI_SHIFT 4
|
||||
#define MV_FDB_LO_SHIFT 12
|
||||
|
||||
#define MV_MIRROR_RX_DEST_MASK 0xf000
|
||||
#define MV_MIRROR_TX_DEST_MASK 0x0f00
|
||||
#define MV_MIRROR_RX_DEST_SHIFT 12
|
||||
#define MV_MIRROR_TX_DEST_SHIFT 8
|
||||
|
||||
#define MV_MIRROR_RX_SRC_SHIFT 4
|
||||
#define MV_MIRROR_RX_SRC_MASK (1 << MV_MIRROR_RX_SRC_SHIFT)
|
||||
#define MV_MIRROR_TX_SRC_SHIFT 5
|
||||
#define MV_MIRROR_TX_SRC_MASK (1 << MV_MIRROR_TX_SRC_SHIFT)
|
||||
|
||||
/* Marvell Specific PHY register */
|
||||
#define MII_MV_SPEC_CTRL 16
|
||||
enum {
|
||||
@ -284,6 +295,12 @@ struct mvsw61xx_state {
|
||||
u32 port_sstate;
|
||||
} vlans[MV_VLANS];
|
||||
|
||||
/* mirroring */
|
||||
bool mirror_rx;
|
||||
bool mirror_tx;
|
||||
int source_port;
|
||||
int monitor_port;
|
||||
|
||||
char buf[128];
|
||||
};
|
||||
|
||||
|
@ -1553,8 +1553,8 @@ int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
|
||||
|
||||
smi->ext_mbus = of_mdio_find_bus(mdio_node);
|
||||
if (!smi->ext_mbus) {
|
||||
dev_err(&pdev->dev,
|
||||
"cannot find mdio bus from bus handle");
|
||||
dev_info(&pdev->dev,
|
||||
"cannot find mdio bus from bus handle (yet)");
|
||||
goto try_gpio;
|
||||
}
|
||||
|
||||
@ -1562,8 +1562,12 @@ int rtl8366_smi_probe_of(struct platform_device *pdev, struct rtl8366_smi *smi)
|
||||
|
||||
try_gpio:
|
||||
if (!gpio_is_valid(sck) || !gpio_is_valid(sda)) {
|
||||
dev_err(&pdev->dev, "gpios missing in devictree\n");
|
||||
return -EINVAL;
|
||||
if (!mdio_node) {
|
||||
dev_err(&pdev->dev, "gpios missing in devictree\n");
|
||||
return -EINVAL;
|
||||
} else {
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
}
|
||||
|
||||
smi->gpio_sda = sda;
|
||||
@ -1619,7 +1623,7 @@ struct rtl8366_smi *rtl8366_smi_probe(struct platform_device *pdev)
|
||||
|
||||
free_smi:
|
||||
kfree(smi);
|
||||
return NULL;
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(rtl8366_smi_probe);
|
||||
|
||||
|
@ -1445,8 +1445,8 @@ static int rtl8366rb_probe(struct platform_device *pdev)
|
||||
" version " RTL8366RB_DRIVER_VER"\n");
|
||||
|
||||
smi = rtl8366_smi_probe(pdev);
|
||||
if (!smi)
|
||||
return -ENODEV;
|
||||
if (IS_ERR(smi))
|
||||
return PTR_ERR(smi);
|
||||
|
||||
smi->clk_delay = 10;
|
||||
smi->cmd_read = 0xa9;
|
||||
|
@ -1233,8 +1233,8 @@ static int rtl8366s_probe(struct platform_device *pdev)
|
||||
" version " RTL8366S_DRIVER_VER"\n");
|
||||
|
||||
smi = rtl8366_smi_probe(pdev);
|
||||
if (!smi)
|
||||
return -ENODEV;
|
||||
if (IS_ERR(smi))
|
||||
return PTR_ERR(smi);
|
||||
|
||||
smi->clk_delay = 10;
|
||||
smi->cmd_read = 0xa9;
|
||||
|
@ -1752,8 +1752,8 @@ static int rtl8367_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
|
||||
smi = rtl8366_smi_probe(pdev);
|
||||
if (!smi)
|
||||
return -ENODEV;
|
||||
if (IS_ERR(smi))
|
||||
return PTR_ERR(smi);
|
||||
|
||||
smi->clk_delay = 1500;
|
||||
smi->cmd_read = 0xb9;
|
||||
|
@ -1401,7 +1401,7 @@ static int rtl8367b_switch_init(struct rtl8366_smi *smi)
|
||||
int err;
|
||||
|
||||
dev->name = "RTL8367B";
|
||||
dev->cpu_port = RTL8367B_CPU_PORT_NUM;
|
||||
dev->cpu_port = smi->cpu_port;
|
||||
dev->ports = RTL8367B_NUM_PORTS;
|
||||
dev->vlans = RTL8367B_NUM_VIDS;
|
||||
dev->ops = &rtl8367b_sw_ops;
|
||||
@ -1527,15 +1527,17 @@ static int rtl8367b_probe(struct platform_device *pdev)
|
||||
int err;
|
||||
|
||||
smi = rtl8366_smi_probe(pdev);
|
||||
if (!smi)
|
||||
return -ENODEV;
|
||||
if (IS_ERR(smi))
|
||||
return PTR_ERR(smi);
|
||||
|
||||
smi->clk_delay = 1500;
|
||||
smi->cmd_read = 0xb9;
|
||||
smi->cmd_write = 0xb8;
|
||||
smi->ops = &rtl8367b_smi_ops;
|
||||
smi->cpu_port = RTL8367B_CPU_PORT_NUM;
|
||||
smi->num_ports = RTL8367B_NUM_PORTS;
|
||||
if (of_property_read_u32(pdev->dev.of_node, "cpu_port", &smi->cpu_port)
|
||||
|| smi->cpu_port >= smi->num_ports)
|
||||
smi->cpu_port = RTL8367B_CPU_PORT_NUM;
|
||||
smi->num_vlan_mc = RTL8367B_NUM_VLANS;
|
||||
smi->mib_counters = rtl8367b_mib_counters;
|
||||
smi->num_mib_counters = ARRAY_SIZE(rtl8367b_mib_counters);
|
||||
|
@ -274,19 +274,16 @@ static ssize_t swconfig_trig_mode_store(struct device *dev,
|
||||
static DEVICE_ATTR(mode, 0644, swconfig_trig_mode_show,
|
||||
swconfig_trig_mode_store);
|
||||
|
||||
static void
|
||||
static int
|
||||
swconfig_trig_activate(struct led_classdev *led_cdev)
|
||||
{
|
||||
struct switch_led_trigger *sw_trig;
|
||||
struct swconfig_trig_data *trig_data;
|
||||
int err;
|
||||
|
||||
if (led_cdev->trigger->activate != swconfig_trig_activate)
|
||||
return;
|
||||
|
||||
trig_data = kzalloc(sizeof(struct swconfig_trig_data), GFP_KERNEL);
|
||||
if (!trig_data)
|
||||
return;
|
||||
return -ENOMEM;
|
||||
|
||||
sw_trig = (void *) led_cdev->trigger;
|
||||
|
||||
@ -309,7 +306,7 @@ swconfig_trig_activate(struct led_classdev *led_cdev)
|
||||
if (err)
|
||||
goto err_mode_free;
|
||||
|
||||
return;
|
||||
return 0;
|
||||
|
||||
err_mode_free:
|
||||
device_remove_file(led_cdev->dev, &dev_attr_speed_mask);
|
||||
@ -320,8 +317,18 @@ err_dev_free:
|
||||
err_free:
|
||||
led_cdev->trigger_data = NULL;
|
||||
kfree(trig_data);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0)
|
||||
static void
|
||||
swconfig_trig_activate_void(struct led_classdev *led_cdev)
|
||||
{
|
||||
swconfig_trig_activate(led_cdev);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void
|
||||
swconfig_trig_deactivate(struct led_classdev *led_cdev)
|
||||
{
|
||||
@ -516,7 +523,11 @@ swconfig_create_led_trigger(struct switch_dev *swdev)
|
||||
|
||||
sw_trig->swdev = swdev;
|
||||
sw_trig->trig.name = swdev->devname;
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4,19,0)
|
||||
sw_trig->trig.activate = swconfig_trig_activate_void;
|
||||
#else
|
||||
sw_trig->trig.activate = swconfig_trig_activate;
|
||||
#endif
|
||||
sw_trig->trig.deactivate = swconfig_trig_deactivate;
|
||||
|
||||
INIT_DELAYED_WORK(&sw_trig->sw_led_work, swconfig_led_work_func);
|
||||
|
@ -1,36 +0,0 @@
|
||||
/*
|
||||
* B53 platform data
|
||||
*
|
||||
* Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and/or distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef __B53_H
|
||||
#define __B53_H
|
||||
|
||||
#include <linux/kernel.h>
|
||||
|
||||
struct b53_platform_data {
|
||||
u32 chip_id;
|
||||
u16 enabled_ports;
|
||||
|
||||
/* allow to specify an ethX alias */
|
||||
const char *alias;
|
||||
|
||||
/* only used by MMAP'd driver */
|
||||
unsigned big_endian:1;
|
||||
void __iomem *regs;
|
||||
};
|
||||
|
||||
#endif
|
@ -126,3 +126,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
|
||||
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
|
||||
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
|
||||
--- a/include/linux/platform_data/b53.h
|
||||
+++ b/include/linux/platform_data/b53.h
|
||||
@@ -25,6 +25,9 @@ struct b53_platform_data {
|
||||
u32 chip_id;
|
||||
u16 enabled_ports;
|
||||
|
||||
+ /* allow to specify an ethX alias */
|
||||
+ const char *alias;
|
||||
+
|
||||
/* only used by MMAP'd driver */
|
||||
unsigned big_endian:1;
|
||||
void __iomem *regs;
|
||||
|
@ -0,0 +1,83 @@
|
||||
From c942c462411e4757aafba73bf13b5e5c7a4b62ca Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Sun, 23 Dec 2018 00:38:55 +0100
|
||||
Subject: [PATCH] mtd: rawnand: qcom: fix memory corruption that causes panic
|
||||
|
||||
This patch fixes a memory corruption that occured in the
|
||||
qcom-nandc driver since it was converted to nand_scan().
|
||||
|
||||
On boot, an affected device will panic from a NPE at a weird place:
|
||||
| Unable to handle kernel NULL pointer dereference at virtual address 00000000
|
||||
| pgd = (ptrval)
|
||||
| [00000000] *pgd=00000000
|
||||
| Internal error: Oops: 80000005 [#1] SMP ARM
|
||||
| CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.19.9 #0
|
||||
| Hardware name: Generic DT based system
|
||||
| PC is at (null)
|
||||
| LR is at nand_block_isbad+0x90/0xa4
|
||||
| pc : [<00000000>] lr : [<c0592240>] psr: 80000013
|
||||
| sp : cf839d40 ip : 00000000 fp : cfae9e20
|
||||
| r10: cf815810 r9 : 00000000 r8 : 00000000
|
||||
| r7 : 00000000 r6 : 00000000 r5 : 00000001 r4 : cf815810
|
||||
| r3 : 00000000 r2 : cfae9810 r1 : ffffffff r0 : cf815810
|
||||
| Flags: Nzcv IRQs on FIQs on Mode SVC_32 ISA ARM Segment none
|
||||
| Control: 10c5387d Table: 8020406a DAC: 00000051
|
||||
| Process swapper/0 (pid: 1, stack limit = 0x(ptrval))
|
||||
| [<c0592240>] (nand_block_isbad) from [<c0580a94>] (allocate_partition+0x7a0/0x7dc)
|
||||
| [<c0580a94>] (allocate_partition) from [<c05811e4>] (add_mtd_partitions+0x58/0x10c)
|
||||
| [<c05811e4>] (add_mtd_partitions) from [<c0581164>] (parse_mtd_partitions+0x310/0x338)
|
||||
| [<c0581164>] (parse_mtd_partitions) from [<c057def4>] (mtd_device_parse_register+0x60/0x15c)
|
||||
| [<c057def4>] (mtd_device_parse_register) from [<c059d274>] (qcom_nandc_probe+0x770/0x8f4)
|
||||
| [<c059d274>] (qcom_nandc_probe) from [<c0567f00>] (platform_drv_probe+0x34/0x70)
|
||||
|
||||
The problem is that the nand_scan()'s qcom_nand_attach_chip callback
|
||||
is updating the nandc->max_cwperpage from 1 to 4. This causes the
|
||||
sg_init_table of clear_bam_transaction() in the driver's
|
||||
qcom_nandc_block_bad() to memset much more than what was initially
|
||||
allocated by alloc_bam_transaction().
|
||||
|
||||
Hence, this patch restores the old behavior by performing the
|
||||
alloc_bam_transaction() after the chip was identified.
|
||||
|
||||
Fixes: 6a3cec64f18c ("mtd: rawnand: qcom: convert driver to nand_scan()")
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
drivers/mtd/nand/raw/qcom_nandc.c | 20 ++++++++++----------
|
||||
1 file changed, 10 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/raw/qcom_nandc.c
|
||||
+++ b/drivers/mtd/nand/raw/qcom_nandc.c
|
||||
@@ -2839,6 +2839,16 @@ static int qcom_nand_host_init_and_regis
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
+ if (nandc->props->is_bam) {
|
||||
+ free_bam_transaction(nandc);
|
||||
+ nandc->bam_txn = alloc_bam_transaction(nandc);
|
||||
+ if (!nandc->bam_txn) {
|
||||
+ dev_err(nandc->dev,
|
||||
+ "failed to allocate bam transaction\n");
|
||||
+ return -ENOMEM;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
ret = mtd_device_register(mtd, NULL, 0);
|
||||
if (ret)
|
||||
nand_cleanup(chip);
|
||||
@@ -2853,16 +2863,6 @@ static int qcom_probe_nand_devices(struc
|
||||
struct qcom_nand_host *host;
|
||||
int ret;
|
||||
|
||||
- if (nandc->props->is_bam) {
|
||||
- free_bam_transaction(nandc);
|
||||
- nandc->bam_txn = alloc_bam_transaction(nandc);
|
||||
- if (!nandc->bam_txn) {
|
||||
- dev_err(nandc->dev,
|
||||
- "failed to allocate bam transaction\n");
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
- }
|
||||
-
|
||||
for_each_available_child_of_node(dn, child) {
|
||||
host = devm_kzalloc(dev, sizeof(*host), GFP_KERNEL);
|
||||
if (!host) {
|
@ -0,0 +1,84 @@
|
||||
From 38a3549ffc0033761063cc5c7b994ab075694db8 Mon Sep 17 00:00:00 2001
|
||||
From: Christian Lamparter <chunkeey@gmail.com>
|
||||
Date: Tue, 25 Dec 2018 21:11:08 +0100
|
||||
Subject: [RFC PATCH] leds: fix regression in usbport led trigger
|
||||
|
||||
In the patch "usb: simplify usbport trigger" together with
|
||||
"leds: triggers: add device attribute support" caused an
|
||||
regression for the usbport trigger. it will no longer
|
||||
enumerate any "ports" (i.e the sysfs directory stays empty)
|
||||
if the usb host drivers are fully initialized before the
|
||||
usbport trigger was loaded.
|
||||
|
||||
The reason is that the usbport driver registers the sysfs
|
||||
entries in the ports subdirectory during the activate()
|
||||
callback. Whereas the patch
|
||||
"leds: triggers: add device attribute support" made it so
|
||||
that the sysfs "ports" group was only being added after
|
||||
the activate() callback succeeded.
|
||||
|
||||
This patch moves the device_add_groups() in front of the
|
||||
call to the trigger's activate() function in order to
|
||||
solve the problem.
|
||||
|
||||
Fixes: 6f7b0bad8839 ("usb: simplify usbport trigger")
|
||||
Signed-off-by: Christian Lamparter <chunkeey@gmail.com>
|
||||
---
|
||||
drivers/leds/led-triggers.c | 19 ++++++++++---------
|
||||
1 file changed, 10 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/drivers/leds/led-triggers.c b/drivers/leds/led-triggers.c
|
||||
index 17d73db1456e..08e7c724a9dc 100644
|
||||
--- a/drivers/leds/led-triggers.c
|
||||
+++ b/drivers/leds/led-triggers.c
|
||||
@@ -134,6 +134,12 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
}
|
||||
if (trig) {
|
||||
+ ret = device_add_groups(led_cdev->dev, trig->groups);
|
||||
+ if (ret) {
|
||||
+ dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
|
||||
+ goto err_add_groups;
|
||||
+ }
|
||||
+
|
||||
write_lock_irqsave(&trig->leddev_list_lock, flags);
|
||||
list_add_tail(&led_cdev->trig_list, &trig->led_cdevs);
|
||||
write_unlock_irqrestore(&trig->leddev_list_lock, flags);
|
||||
@@ -146,12 +152,6 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
|
||||
if (ret)
|
||||
goto err_activate;
|
||||
-
|
||||
- ret = device_add_groups(led_cdev->dev, trig->groups);
|
||||
- if (ret) {
|
||||
- dev_err(led_cdev->dev, "Failed to add trigger attributes\n");
|
||||
- goto err_add_groups;
|
||||
- }
|
||||
}
|
||||
|
||||
if (event) {
|
||||
@@ -165,17 +165,18 @@ int led_trigger_set(struct led_classdev *led_cdev, struct led_trigger *trig)
|
||||
|
||||
return 0;
|
||||
|
||||
-err_add_groups:
|
||||
-
|
||||
+err_activate:
|
||||
+ device_remove_groups(led_cdev->dev, trig->groups);
|
||||
if (trig->deactivate)
|
||||
trig->deactivate(led_cdev);
|
||||
-err_activate:
|
||||
|
||||
led_cdev->trigger = NULL;
|
||||
led_cdev->trigger_data = NULL;
|
||||
write_lock_irqsave(&led_cdev->trigger->leddev_list_lock, flags);
|
||||
list_del(&led_cdev->trig_list);
|
||||
write_unlock_irqrestore(&led_cdev->trigger->leddev_list_lock, flags);
|
||||
+
|
||||
+err_add_groups:
|
||||
led_set_brightness(led_cdev, LED_OFF);
|
||||
|
||||
return ret;
|
||||
--
|
||||
2.20.1
|
||||
|
@ -136,3 +136,15 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
header-y += synclink.h
|
||||
header-y += sync_file.h
|
||||
header-y += sysctl.h
|
||||
--- a/include/linux/platform_data/b53.h
|
||||
+++ b/include/linux/platform_data/b53.h
|
||||
@@ -25,6 +25,9 @@ struct b53_platform_data {
|
||||
u32 chip_id;
|
||||
u16 enabled_ports;
|
||||
|
||||
+ /* allow to specify an ethX alias */
|
||||
+ const char *alias;
|
||||
+
|
||||
/* only used by MMAP'd driver */
|
||||
unsigned big_endian:1;
|
||||
void __iomem *regs;
|
||||
|
@ -19,3 +19,42 @@
|
||||
obj-$(CONFIG_FIXED_PHY) += fixed.o
|
||||
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
|
||||
obj-$(CONFIG_MDIO_GPIO) += mdio-gpio.o
|
||||
--- /dev/null
|
||||
+++ b/linux/platform_data/b53.h
|
||||
@@ -0,0 +1,36 @@
|
||||
+/*
|
||||
+ * B53 platform data
|
||||
+ *
|
||||
+ * Copyright (C) 2013 Jonas Gorski <jogo@openwrt.org>
|
||||
+ *
|
||||
+ * Permission to use, copy, modify, and/or distribute this software for any
|
||||
+ * purpose with or without fee is hereby granted, provided that the above
|
||||
+ * copyright notice and this permission notice appear in all copies.
|
||||
+ *
|
||||
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
+ */
|
||||
+
|
||||
+#ifndef __B53_H
|
||||
+#define __B53_H
|
||||
+
|
||||
+#include <linux/kernel.h>
|
||||
+
|
||||
+struct b53_platform_data {
|
||||
+ u32 chip_id;
|
||||
+ u16 enabled_ports;
|
||||
+
|
||||
+ /* allow to specify an ethX alias */
|
||||
+ const char *alias;
|
||||
+
|
||||
+ /* only used by MMAP'd driver */
|
||||
+ unsigned big_endian:1;
|
||||
+ void __iomem *regs;
|
||||
+};
|
||||
+
|
||||
+#endif
|
||||
|
@ -1,21 +0,0 @@
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -108,4 +108,11 @@ config LEDS_TRIGGER_CAMERA
|
||||
This enables direct flash/torch on/off by the driver, kernel space.
|
||||
If unsure, say Y.
|
||||
|
||||
+config LEDS_TRIGGER_NETDEV
|
||||
+ tristate "LED Netdev Trigger"
|
||||
+ depends on NET && LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This allows LEDs to be controlled by network device activity.
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
endif # LEDS_TRIGGERS
|
||||
--- a/drivers/leds/Makefile
|
||||
+++ b/drivers/leds/Makefile
|
||||
@@ -62,3 +62,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d
|
||||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGERS) += trigger/
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
@ -0,0 +1,51 @@
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
To: linux-f2fs-devel@lists.sourceforge.net, yuchao0@huawei.com,
|
||||
jaegeuk@kernel.org
|
||||
Subject: [PATCH v2 1/1] f2fs: fix validation of the block count in
|
||||
sanity_check_raw_super
|
||||
Date: Sat, 22 Dec 2018 11:22:26 +0100
|
||||
Message-Id: <20181222102226.10050-2-martin.blumenstingl@googlemail.com>
|
||||
|
||||
Treat "block_count" from struct f2fs_super_block as 64-bit little endian
|
||||
value in sanity_check_raw_super() because struct f2fs_super_block
|
||||
declares "block_count" as "__le64".
|
||||
|
||||
This fixes a bug where the superblock validation fails on big endian
|
||||
devices with the following error:
|
||||
F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
|
||||
F2FS-fs (sda1): Can't find valid F2FS filesystem in 1th superblock
|
||||
F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
|
||||
F2FS-fs (sda1): Can't find valid F2FS filesystem in 2th superblock
|
||||
As result of this the partition cannot be mounted.
|
||||
|
||||
With this patch applied the superblock validation works fine and the
|
||||
partition can be mounted again:
|
||||
F2FS-fs (sda1): Mounted with checkpoint version = 7c84
|
||||
|
||||
My little endian x86-64 hardware was able to mount the partition without
|
||||
this fix.
|
||||
To confirm that mounting f2fs filesystems works on big endian machines
|
||||
again I tested this on a 32-bit MIPS big endian (lantiq) device.
|
||||
|
||||
Fixes: 0cfe75c5b01199 ("f2fs: enhance sanity_check_raw_super() to avoid potential overflows")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Chao Yu <yuchao0@huawei.com>
|
||||
---
|
||||
|
||||
--- a/fs/f2fs/super.c
|
||||
+++ b/fs/f2fs/super.c
|
||||
@@ -1897,10 +1897,10 @@ static int sanity_check_raw_super(struct
|
||||
return 1;
|
||||
}
|
||||
|
||||
- if (segment_count > (le32_to_cpu(raw_super->block_count) >> 9)) {
|
||||
+ if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
- "Wrong segment_count / block_count (%u > %u)",
|
||||
- segment_count, le32_to_cpu(raw_super->block_count));
|
||||
+ "Wrong segment_count / block_count (%u > %llu)",
|
||||
+ segment_count, le64_to_cpu(raw_super->block_count));
|
||||
return 1;
|
||||
}
|
||||
|
@ -1,30 +0,0 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: MIPS: fix cache flushing for highmem pages
|
||||
|
||||
Most cache flush ops were no-op for highmem pages. This led to nasty
|
||||
segfaults and (in the case of page_address(page) == NULL) kernel
|
||||
crashes.
|
||||
|
||||
Fix this by always flushing highmem pages using kmap/kunmap_atomic
|
||||
around the actual cache flush. This might be a bit inefficient, but at
|
||||
least it's stable.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/mips/mm/cache.c
|
||||
+++ b/arch/mips/mm/cache.c
|
||||
@@ -116,6 +116,13 @@ void __flush_anon_page(struct page *page
|
||||
{
|
||||
unsigned long addr = (unsigned long) page_address(page);
|
||||
|
||||
+ if (PageHighMem(page)) {
|
||||
+ addr = (unsigned long)kmap_atomic(page);
|
||||
+ flush_data_cache_page(addr);
|
||||
+ __kunmap_atomic((void *)addr);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
if (pages_do_alias(addr, vmaddr)) {
|
||||
if (page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||
void *kaddr;
|
@ -0,0 +1,49 @@
|
||||
From: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Subject: [PATCH v2 1/1] f2fs: fix validation of the block count in
|
||||
sanity_check_raw_super
|
||||
Date: Sat, 22 Dec 2018 11:22:26 +0100
|
||||
Message-Id: <20181222102226.10050-2-martin.blumenstingl@googlemail.com>
|
||||
|
||||
Treat "block_count" from struct f2fs_super_block as 64-bit little endian
|
||||
value in sanity_check_raw_super() because struct f2fs_super_block
|
||||
declares "block_count" as "__le64".
|
||||
|
||||
This fixes a bug where the superblock validation fails on big endian
|
||||
devices with the following error:
|
||||
F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
|
||||
F2FS-fs (sda1): Can't find valid F2FS filesystem in 1th superblock
|
||||
F2FS-fs (sda1): Wrong segment_count / block_count (61439 > 0)
|
||||
F2FS-fs (sda1): Can't find valid F2FS filesystem in 2th superblock
|
||||
As result of this the partition cannot be mounted.
|
||||
|
||||
With this patch applied the superblock validation works fine and the
|
||||
partition can be mounted again:
|
||||
F2FS-fs (sda1): Mounted with checkpoint version = 7c84
|
||||
|
||||
My little endian x86-64 hardware was able to mount the partition without
|
||||
this fix.
|
||||
To confirm that mounting f2fs filesystems works on big endian machines
|
||||
again I tested this on a 32-bit MIPS big endian (lantiq) device.
|
||||
|
||||
Fixes: 0cfe75c5b01199 ("f2fs: enhance sanity_check_raw_super() to avoid potential overflows")
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Martin Blumenstingl <martin.blumenstingl@googlemail.com>
|
||||
Reviewed-by: Chao Yu <yuchao0@huawei.com>
|
||||
---
|
||||
|
||||
--- a/fs/f2fs/super.c
|
||||
+++ b/fs/f2fs/super.c
|
||||
@@ -2267,10 +2267,10 @@ static int sanity_check_raw_super(struct
|
||||
return 1;
|
||||
}
|
||||
|
||||
- if (segment_count > (le32_to_cpu(raw_super->block_count) >> 9)) {
|
||||
+ if (segment_count > (le64_to_cpu(raw_super->block_count) >> 9)) {
|
||||
f2fs_msg(sb, KERN_INFO,
|
||||
- "Wrong segment_count / block_count (%u > %u)",
|
||||
- segment_count, le32_to_cpu(raw_super->block_count));
|
||||
+ "Wrong segment_count / block_count (%u > %llu)",
|
||||
+ segment_count, le64_to_cpu(raw_super->block_count));
|
||||
return 1;
|
||||
}
|
||||
|
@ -68,7 +68,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
mtd_add_partition_attrs(new);
|
||||
|
||||
@@ -728,6 +733,35 @@ int mtd_del_partition(struct mtd_info *m
|
||||
@@ -728,6 +733,29 @@ int mtd_del_partition(struct mtd_info *m
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_del_partition);
|
||||
|
||||
@ -82,11 +82,6 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
|
||||
+ int offset, int size)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
|
||||
+{
|
||||
+ static int rootfs_found = 0;
|
||||
@ -94,17 +89,16 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
+ if (rootfs_found)
|
||||
+ return;
|
||||
+
|
||||
+ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||
+ IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||
+ if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
|
||||
+ !strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||
+ !of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL))
|
||||
+ split_firmware(master, part);
|
||||
+
|
||||
+ arch_split_mtd_part(master, part->mtd.name, part->offset,
|
||||
+ part->mtd.size);
|
||||
+}
|
||||
+
|
||||
/*
|
||||
* This function, given a master MTD object and a partition table, creates
|
||||
* and registers slave MTD objects which are bound to the master according to
|
||||
@@ -759,6 +793,7 @@ int add_mtd_partitions(struct mtd_info *
|
||||
@@ -759,6 +787,7 @@ int add_mtd_partitions(struct mtd_info *
|
||||
mutex_unlock(&mtd_partitions_mutex);
|
||||
|
||||
add_mtd_device(&slave->mtd);
|
||||
@ -112,13 +106,3 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
mtd_add_partition_attrs(slave);
|
||||
/* Look for subpartitions */
|
||||
parse_mtd_partitions(&slave->mtd, parts[i].types, NULL);
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -110,5 +110,7 @@ int mtd_add_partition(struct mtd_info *m
|
||||
long long offset, long long length);
|
||||
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||
+extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||
+ const char *name, int offset, int size);
|
||||
|
||||
#endif
|
||||
|
@ -57,7 +57,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||
#else
|
||||
@@ -1115,6 +1149,61 @@ void mtd_part_parser_cleanup(struct mtd_
|
||||
@@ -1109,6 +1143,61 @@ void mtd_part_parser_cleanup(struct mtd_
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -17,8 +17,8 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
|
||||
}
|
||||
|
||||
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
|
||||
@@ -789,6 +790,12 @@ static void mtd_partition_split(struct m
|
||||
static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
|
||||
@@ -784,6 +785,12 @@ static void mtd_partition_split(struct m
|
||||
if (rootfs_found)
|
||||
return;
|
||||
|
||||
@ -28,9 +28,9 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
+ rootfs_found = 1;
|
||||
+ }
|
||||
+
|
||||
if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||
IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||
split_firmware(master, part);
|
||||
if (IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE) &&
|
||||
!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||
!of_find_property(mtd_get_of_node(&part->mtd), "compatible", NULL))
|
||||
--- a/include/linux/mtd/partitions.h
|
||||
+++ b/include/linux/mtd/partitions.h
|
||||
@@ -75,6 +75,8 @@ struct mtd_part_parser_data {
|
||||
|
@ -11,7 +11,7 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -1228,6 +1228,24 @@ int mtd_is_partition(const struct mtd_in
|
||||
@@ -1222,6 +1222,24 @@ int mtd_is_partition(const struct mtd_in
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(mtd_is_partition);
|
||||
|
||||
@ -72,5 +72,5 @@ Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
|
||||
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
|
||||
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||
extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||
const char *name, int offset, int size);
|
||||
|
||||
#endif
|
||||
|
@ -1,74 +0,0 @@
|
||||
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
Subject: usb: Remove annoying warning about bogus URB
|
||||
|
||||
When ath9k-htc Wi-Fi dongle is used with generic OHCI controller
|
||||
infinite stream of warnings appears in debug console like this:
|
||||
-------------------------->8----------------------
|
||||
usb 1-1: new full-speed USB device number 2 using ohci-platform
|
||||
usb 1-1: ath9k_htc: Firmware ath9k_htc/htc_9271-1.4.0.fw requested
|
||||
usb 1-1: ath9k_htc: Transferred FW: ath9k_htc/htc_9271-1.4.0.fw, size:
|
||||
51008
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Not tainted
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc2 ]---
|
||||
------------[ cut here ]------------
|
||||
WARNING: CPU: 0 PID: 19 at drivers/usb/core/urb.c:449
|
||||
usb_submit_urb+0x1b4/0x498()
|
||||
usb 1-1: BOGUS urb xfer, pipe 1 != type 3
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 19 Comm: kworker/0:1 Tainted: G W
|
||||
4.4.0-rc4-00017-g00e2d79-dirty #3
|
||||
Workqueue: events request_firmware_work_func
|
||||
|
||||
Stack Trace:
|
||||
arc_unwind_core.constprop.1+0xa4/0x110
|
||||
---[ end trace 649ef8c342817fc3 ]---
|
||||
------------[ cut here ]------------
|
||||
-------------------------->8----------------------
|
||||
|
||||
There're some discussions in mailing lists proposing to disable
|
||||
that particular check alltogether and magically all seem to work
|
||||
fine with muted warning.
|
||||
|
||||
Anyways new thread on that regard could be found here:
|
||||
http://lists.infradead.org/pipermail/linux-snps-arc/2016-July/001310.html
|
||||
|
||||
Let's see what comes out of that new discussion, hopefully patching
|
||||
of generic USB stuff won't be required then.
|
||||
|
||||
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||
---
|
||||
drivers/leds/Makefile | 1 +
|
||||
drivers/leds/trigger/Kconfig | 7 +++++++
|
||||
2 files changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/leds/Makefile
|
||||
+++ b/drivers/leds/Makefile
|
||||
@@ -77,3 +77,4 @@ obj-$(CONFIG_LEDS_DAC124S085) += leds-d
|
||||
|
||||
# LED Triggers
|
||||
obj-$(CONFIG_LEDS_TRIGGERS) += trigger/
|
||||
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o
|
||||
--- a/drivers/leds/trigger/Kconfig
|
||||
+++ b/drivers/leds/trigger/Kconfig
|
||||
@@ -126,4 +126,11 @@ config LEDS_TRIGGER_PANIC
|
||||
a different trigger.
|
||||
If unsure, say Y.
|
||||
|
||||
+config LEDS_TRIGGER_NETDEV
|
||||
+ tristate "LED Netdev Trigger"
|
||||
+ depends on NET && LEDS_TRIGGERS
|
||||
+ help
|
||||
+ This allows LEDs to be controlled by network device activity.
|
||||
+ If unsure, say Y.
|
||||
+
|
||||
endif # LEDS_TRIGGERS
|
@ -384,7 +384,6 @@ CONFIG_NVRAM=y
|
||||
CONFIG_OLD_SIGACTION=y
|
||||
CONFIG_OLD_SIGSUSPEND3=y
|
||||
CONFIG_OPROFILE_NMI_TIMER=y
|
||||
# CONFIG_OPTIMIZE_INLINING is not set
|
||||
CONFIG_OUTPUT_FORMAT="elf32-i386"
|
||||
CONFIG_PADATA=y
|
||||
CONFIG_PAGE_OFFSET=0xC0000000
|
||||
@ -446,6 +445,7 @@ CONFIG_SATA_AHCI_PLATFORM=y
|
||||
CONFIG_SATA_MV=y
|
||||
CONFIG_SATA_NV=y
|
||||
CONFIG_SATA_VIA=y
|
||||
# CONFIG_SATA_ZPODD is not set
|
||||
# CONFIG_SBC7240_WDT is not set
|
||||
# CONFIG_SBC8360_WDT is not set
|
||||
# CONFIG_SBC_EPX_C3_WATCHDOG is not set
|
||||
@ -593,4 +593,3 @@ CONFIG_XPS=y
|
||||
CONFIG_XZ_DEC_BCJ=y
|
||||
CONFIG_XZ_DEC_X86=y
|
||||
CONFIG_ZLIB_INFLATE=y
|
||||
# CONFIG_SATA_ZPODD is not set
|
||||
|
Loading…
Reference in New Issue
Block a user