kernel: init kernel 5.4 support
This commit is contained in:
parent
387c09fb6f
commit
9cbd449674
@ -9,10 +9,12 @@ endif
|
||||
LINUX_VERSION-4.9 = .218
|
||||
LINUX_VERSION-4.14 = .175
|
||||
LINUX_VERSION-4.19 = .114
|
||||
LINUX_VERSION-5.4 = .31
|
||||
|
||||
LINUX_KERNEL_HASH-4.9.218 = df3a6e615ec4c57b04775e9c018c67045223ac662e696d28fd37baa5114349cd
|
||||
LINUX_KERNEL_HASH-4.14.175 = cb440ac5d20071dcb482e5062958514064b0c5a8375c92653062ea201ae0222c
|
||||
LINUX_KERNEL_HASH-4.19.114 = 1e40a0dc6afc95a259f97b80d5f5ef8f89e2ee49e993ba6844e2bc55de361f0e
|
||||
LINUX_KERNEL_HASH-5.4.31 = a11083f8f809887f6a0f8d4467532385b99418f17998fe6e837807491c276eeb
|
||||
|
||||
remove_uri_prefix=$(subst git://,,$(subst http://,,$(subst https://,,$(1))))
|
||||
sanitize_uri=$(call qstrip,$(subst @,_,$(subst :,_,$(subst .,_,$(subst -,_,$(subst /,_,$(1)))))))
|
||||
|
||||
@ -0,0 +1,30 @@
|
||||
From 13b1ecc3401653a355798eb1dee10cc1608202f4 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Mon, 18 Jan 2016 12:27:49 +0100
|
||||
Subject: [PATCH 33/34] Kbuild: don't hardcode path to awk in
|
||||
scripts/ld-version.sh
|
||||
|
||||
On some systems /usr/bin/awk does not exist, or is broken. Find it via
|
||||
$PATH instead.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
scripts/ld-version.sh | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/scripts/ld-version.sh
|
||||
+++ b/scripts/ld-version.sh
|
||||
@@ -1,6 +1,7 @@
|
||||
-#!/usr/bin/awk -f
|
||||
+#!/bin/sh
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
# extract linker version number from stdin and turn into single number
|
||||
+exec awk '
|
||||
{
|
||||
gsub(".*\\)", "");
|
||||
gsub(".*version ", "");
|
||||
@@ -9,3 +10,4 @@
|
||||
print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
|
||||
exit
|
||||
}
|
||||
+'
|
||||
@ -0,0 +1,24 @@
|
||||
From 173019b66dcc9d68ad9333aa744dad1e369b5aa8 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 9 Jul 2017 00:26:53 +0200
|
||||
Subject: [PATCH 34/34] kernel: add compile fix for linux 4.9 on x86
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
Makefile | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -471,8 +471,9 @@ KBUILD_LDFLAGS :=
|
||||
GCC_PLUGINS_CFLAGS :=
|
||||
CLANG_FLAGS :=
|
||||
|
||||
-export ARCH SRCARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
|
||||
-export CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE PAHOLE LEX YACC AWK INSTALLKERNEL
|
||||
+export ARCH SRCARCH SUBARCH CONFIG_SHELL BASH HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD
|
||||
+export CC CPP AR NM STRIP OBJCOPY OBJDUMP OBJSIZE PAHOLE LEX YACC AWK INSTALLKERNEL
|
||||
+
|
||||
export PERL PYTHON PYTHON2 PYTHON3 CHECK CHECKFLAGS MAKE UTS_MACHINE HOSTCXX
|
||||
export KBUILD_HOSTCXXFLAGS KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS LDFLAGS_MODULE
|
||||
|
||||
@ -0,0 +1,558 @@
|
||||
From 1bb0c3ec899827cfa4668bb63a08713a40744d21 Mon Sep 17 00:00:00 2001
|
||||
From: Florian Westphal <fw@strlen.de>
|
||||
Date: Sun, 9 Jul 2017 08:58:30 +0200
|
||||
Subject: [PATCH] netfilter: conntrack: cache route for forwarded connections
|
||||
|
||||
... to avoid per-packet FIB lookup if possible.
|
||||
|
||||
The cached dst is re-used provided the input interface
|
||||
is the same as that of the previous packet in the same direction.
|
||||
|
||||
If not, the cached dst is invalidated.
|
||||
|
||||
For ipv6 we also need to store sernum, else dst_check doesn't work,
|
||||
pointed out by Eric Dumazet.
|
||||
|
||||
This should speed up forwarding when conntrack is already in use
|
||||
anyway, especially when using reverse path filtering -- active RPF
|
||||
enforces two FIB lookups for each packet.
|
||||
|
||||
Before the routing cache removal this didn't matter since RPF was performed
|
||||
only when route cache didn't yield a result; but without route cache it
|
||||
comes at higher price.
|
||||
|
||||
Julian Anastasov suggested to add NETDEV_UNREGISTER handler to
|
||||
avoid holding on to dsts of 'frozen' conntracks.
|
||||
|
||||
Signed-off-by: Florian Westphal <fw@strlen.de>
|
||||
---
|
||||
include/net/netfilter/nf_conntrack_extend.h | 4 +
|
||||
include/net/netfilter/nf_conntrack_rtcache.h | 34 +++
|
||||
net/netfilter/Kconfig | 12 +
|
||||
net/netfilter/Makefile | 3 +
|
||||
net/netfilter/nf_conntrack_rtcache.c | 428 +++++++++++++++++++++++++++
|
||||
5 files changed, 481 insertions(+)
|
||||
create mode 100644 include/net/netfilter/nf_conntrack_rtcache.h
|
||||
create mode 100644 net/netfilter/nf_conntrack_rtcache.c
|
||||
|
||||
--- a/include/net/netfilter/nf_conntrack_extend.h
|
||||
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
||||
@@ -28,6 +28,9 @@ enum nf_ct_ext_id {
|
||||
#if IS_ENABLED(CONFIG_NETFILTER_SYNPROXY)
|
||||
NF_CT_EXT_SYNPROXY,
|
||||
#endif
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
||||
+ NF_CT_EXT_RTCACHE,
|
||||
+#endif
|
||||
NF_CT_EXT_NUM,
|
||||
};
|
||||
|
||||
@@ -40,6 +43,7 @@ enum nf_ct_ext_id {
|
||||
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
|
||||
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
|
||||
#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
|
||||
+#define NF_CT_EXT_RTCACHE_TYPE struct nf_conn_rtcache
|
||||
|
||||
/* Extensions: optional stuff which isn't permanently in struct. */
|
||||
struct nf_ct_ext {
|
||||
--- /dev/null
|
||||
+++ b/include/net/netfilter/nf_conntrack_rtcache.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+#include <linux/gfp.h>
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
||||
+
|
||||
+struct dst_entry;
|
||||
+
|
||||
+struct nf_conn_dst_cache {
|
||||
+ struct dst_entry *dst;
|
||||
+ int iif;
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ u32 cookie;
|
||||
+#endif
|
||||
+
|
||||
+};
|
||||
+
|
||||
+struct nf_conn_rtcache {
|
||||
+ struct nf_conn_dst_cache cached_dst[IP_CT_DIR_MAX];
|
||||
+};
|
||||
+
|
||||
+static inline
|
||||
+struct nf_conn_rtcache *nf_ct_rtcache_find(const struct nf_conn *ct)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_RTCACHE)
|
||||
+ return nf_ct_ext_find(ct, NF_CT_EXT_RTCACHE);
|
||||
+#else
|
||||
+ return NULL;
|
||||
+#endif
|
||||
+}
|
||||
+
|
||||
+static inline int nf_conn_rtcache_iif_get(const struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ return rtc->cached_dst[dir].iif;
|
||||
+}
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -136,6 +136,18 @@ config NF_CONNTRACK_EVENTS
|
||||
|
||||
If unsure, say `N'.
|
||||
|
||||
+config NF_CONNTRACK_RTCACHE
|
||||
+ tristate "Cache route entries in conntrack objects"
|
||||
+ depends on NETFILTER_ADVANCED
|
||||
+ depends on NF_CONNTRACK
|
||||
+ help
|
||||
+ If this option is enabled, the connection tracking code will
|
||||
+ cache routing information for each connection that is being
|
||||
+ forwarded, at a cost of 32 bytes per conntrack object.
|
||||
+
|
||||
+ To compile it as a module, choose M here. If unsure, say N.
|
||||
+ The module will be called nf_conntrack_rtcache.
|
||||
+
|
||||
config NF_CONNTRACK_TIMEOUT
|
||||
bool 'Connection tracking timeout'
|
||||
depends on NETFILTER_ADVANCED
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -26,6 +26,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_OSF) += n
|
||||
# connection tracking
|
||||
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
||||
|
||||
+# optional conntrack route cache extension
|
||||
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
|
||||
+
|
||||
# netlink interface for nf_conntrack
|
||||
obj-$(CONFIG_NF_CT_NETLINK) += nf_conntrack_netlink.o
|
||||
obj-$(CONFIG_NF_CT_NETLINK_TIMEOUT) += nfnetlink_cttimeout.o
|
||||
--- /dev/null
|
||||
+++ b/net/netfilter/nf_conntrack_rtcache.c
|
||||
@@ -0,0 +1,428 @@
|
||||
+/* route cache for netfilter.
|
||||
+ *
|
||||
+ * (C) 2014 Red Hat GmbH
|
||||
+ *
|
||||
+ * This program is free software; you can redistribute it and/or modify
|
||||
+ * it under the terms of the GNU General Public License version 2 as
|
||||
+ * published by the Free Software Foundation.
|
||||
+ */
|
||||
+
|
||||
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/netfilter.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+#include <linux/stddef.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/netdevice.h>
|
||||
+#include <linux/export.h>
|
||||
+#include <linux/module.h>
|
||||
+
|
||||
+#include <net/dst.h>
|
||||
+
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_core.h>
|
||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
||||
+#include <net/netfilter/nf_conntrack_rtcache.h>
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+#include <net/ip6_fib.h>
|
||||
+#endif
|
||||
+
|
||||
+static void __nf_conn_rtcache_destroy(struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ struct dst_entry *dst = rtc->cached_dst[dir].dst;
|
||||
+
|
||||
+ dst_release(dst);
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_destroy(struct nf_conn *ct)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+
|
||||
+ if (!rtc)
|
||||
+ return;
|
||||
+
|
||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_ORIGINAL);
|
||||
+ __nf_conn_rtcache_destroy(rtc, IP_CT_DIR_REPLY);
|
||||
+}
|
||||
+
|
||||
+static void nf_ct_rtcache_ext_add(struct nf_conn *ct)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+
|
||||
+ rtc = nf_ct_ext_add(ct, NF_CT_EXT_RTCACHE, GFP_ATOMIC);
|
||||
+ if (rtc) {
|
||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif = -1;
|
||||
+ rtc->cached_dst[IP_CT_DIR_ORIGINAL].dst = NULL;
|
||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].iif = -1;
|
||||
+ rtc->cached_dst[IP_CT_DIR_REPLY].dst = NULL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static struct nf_conn_rtcache *nf_ct_rtcache_find_usable(struct nf_conn *ct)
|
||||
+{
|
||||
+ return nf_ct_rtcache_find(ct);
|
||||
+}
|
||||
+
|
||||
+static struct dst_entry *
|
||||
+nf_conn_rtcache_dst_get(const struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ return rtc->cached_dst[dir].dst;
|
||||
+}
|
||||
+
|
||||
+static u32 nf_rtcache_get_cookie(int pf, const struct dst_entry *dst)
|
||||
+{
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ if (pf == NFPROTO_IPV6) {
|
||||
+ const struct rt6_info *rt = (const struct rt6_info *)dst;
|
||||
+
|
||||
+ if (rt->from && rt->from->fib6_node)
|
||||
+ return (u32)rt->from->fib6_node->fn_sernum;
|
||||
+ }
|
||||
+#endif
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_dst_set(int pf,
|
||||
+ struct nf_conn_rtcache *rtc,
|
||||
+ struct dst_entry *dst,
|
||||
+ enum ip_conntrack_dir dir, int iif)
|
||||
+{
|
||||
+ if (rtc->cached_dst[dir].iif != iif)
|
||||
+ rtc->cached_dst[dir].iif = iif;
|
||||
+
|
||||
+ if (rtc->cached_dst[dir].dst != dst) {
|
||||
+ struct dst_entry *old;
|
||||
+
|
||||
+ dst_hold(dst);
|
||||
+
|
||||
+ old = xchg(&rtc->cached_dst[dir].dst, dst);
|
||||
+ dst_release(old);
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ if (pf == NFPROTO_IPV6)
|
||||
+ rtc->cached_dst[dir].cookie =
|
||||
+ nf_rtcache_get_cookie(pf, dst);
|
||||
+#endif
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void nf_conn_rtcache_dst_obsolete(struct nf_conn_rtcache *rtc,
|
||||
+ enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ struct dst_entry *old;
|
||||
+
|
||||
+ pr_debug("Invalidate iif %d for dir %d on cache %p\n",
|
||||
+ rtc->cached_dst[dir].iif, dir, rtc);
|
||||
+
|
||||
+ old = xchg(&rtc->cached_dst[dir].dst, NULL);
|
||||
+ dst_release(old);
|
||||
+ rtc->cached_dst[dir].iif = -1;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_in(u_int8_t pf,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ enum ip_conntrack_dir dir;
|
||||
+ struct dst_entry *dst;
|
||||
+ struct nf_conn *ct;
|
||||
+ int iif;
|
||||
+ u32 cookie;
|
||||
+
|
||||
+ if (skb_dst(skb) || skb->sk)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (!ct)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
||||
+ if (!rtc)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ /* if iif changes, don't use cache and let ip stack
|
||||
+ * do route lookup.
|
||||
+ *
|
||||
+ * If rp_filter is enabled it might toss skb, so
|
||||
+ * we don't want to avoid these checks.
|
||||
+ */
|
||||
+ dir = CTINFO2DIR(ctinfo);
|
||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
||||
+ if (state->in->ifindex != iif) {
|
||||
+ pr_debug("ct %p, iif %d, cached iif %d, skip cached entry\n",
|
||||
+ ct, iif, state->in->ifindex);
|
||||
+ return NF_ACCEPT;
|
||||
+ }
|
||||
+ dst = nf_conn_rtcache_dst_get(rtc, dir);
|
||||
+ if (dst == NULL)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ cookie = nf_rtcache_get_cookie(pf, dst);
|
||||
+
|
||||
+ dst = dst_check(dst, cookie);
|
||||
+ pr_debug("obtained dst %p for skb %p, cookie %d\n", dst, skb, cookie);
|
||||
+ if (likely(dst))
|
||||
+ skb_dst_set_noref(skb, dst);
|
||||
+ else
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, dir);
|
||||
+
|
||||
+ return NF_ACCEPT;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward(u_int8_t pf,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ enum ip_conntrack_dir dir;
|
||||
+ struct nf_conn *ct;
|
||||
+ struct dst_entry *dst = skb_dst(skb);
|
||||
+ int iif;
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (!ct)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ if (dst && dst_xfrm(dst))
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ if (!nf_ct_is_confirmed(ct)) {
|
||||
+ if (WARN_ON(nf_ct_rtcache_find(ct)))
|
||||
+ return NF_ACCEPT;
|
||||
+ nf_ct_rtcache_ext_add(ct);
|
||||
+ return NF_ACCEPT;
|
||||
+ }
|
||||
+
|
||||
+ rtc = nf_ct_rtcache_find_usable(ct);
|
||||
+ if (!rtc)
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ dir = CTINFO2DIR(ctinfo);
|
||||
+ iif = nf_conn_rtcache_iif_get(rtc, dir);
|
||||
+ pr_debug("ct %p, skb %p, dir %d, iif %d, cached iif %d\n",
|
||||
+ ct, skb, dir, iif, state->in->ifindex);
|
||||
+ if (likely(state->in->ifindex == iif))
|
||||
+ return NF_ACCEPT;
|
||||
+
|
||||
+ nf_conn_rtcache_dst_set(pf, rtc, skb_dst(skb), dir, state->in->ifindex);
|
||||
+ return NF_ACCEPT;
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_in4(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_in(NFPROTO_IPV4, skb, state);
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward4(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_forward(NFPROTO_IPV4, skb, state);
|
||||
+}
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+static unsigned int nf_rtcache_in6(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_in(NFPROTO_IPV6, skb, state);
|
||||
+}
|
||||
+
|
||||
+static unsigned int nf_rtcache_forward6(void *priv,
|
||||
+ struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ return nf_rtcache_forward(NFPROTO_IPV6, skb, state);
|
||||
+}
|
||||
+#endif
|
||||
+
|
||||
+static int nf_rtcache_dst_remove(struct nf_conn *ct, void *data)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+ struct net_device *dev = data;
|
||||
+
|
||||
+ if (!rtc)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (dev->ifindex == rtc->cached_dst[IP_CT_DIR_ORIGINAL].iif ||
|
||||
+ dev->ifindex == rtc->cached_dst[IP_CT_DIR_REPLY].iif) {
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_ORIGINAL);
|
||||
+ nf_conn_rtcache_dst_obsolete(rtc, IP_CT_DIR_REPLY);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int nf_rtcache_netdev_event(struct notifier_block *this,
|
||||
+ unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+ struct net *net = dev_net(dev);
|
||||
+
|
||||
+ if (event == NETDEV_DOWN)
|
||||
+ nf_ct_iterate_cleanup_net(net, nf_rtcache_dst_remove, dev, 0, 0);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block nf_rtcache_notifier = {
|
||||
+ .notifier_call = nf_rtcache_netdev_event,
|
||||
+};
|
||||
+
|
||||
+static struct nf_hook_ops rtcache_ops[] = {
|
||||
+ {
|
||||
+ .hook = nf_rtcache_in4,
|
||||
+ .pf = NFPROTO_IPV4,
|
||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+ {
|
||||
+ .hook = nf_rtcache_forward4,
|
||||
+ .pf = NFPROTO_IPV4,
|
||||
+ .hooknum = NF_INET_FORWARD,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+#if IS_ENABLED(CONFIG_NF_CONNTRACK_IPV6)
|
||||
+ {
|
||||
+ .hook = nf_rtcache_in6,
|
||||
+ .pf = NFPROTO_IPV6,
|
||||
+ .hooknum = NF_INET_PRE_ROUTING,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+ {
|
||||
+ .hook = nf_rtcache_forward6,
|
||||
+ .pf = NFPROTO_IPV6,
|
||||
+ .hooknum = NF_INET_FORWARD,
|
||||
+ .priority = NF_IP_PRI_LAST,
|
||||
+ },
|
||||
+#endif
|
||||
+};
|
||||
+
|
||||
+static struct nf_ct_ext_type rtcache_extend __read_mostly = {
|
||||
+ .len = sizeof(struct nf_conn_rtcache),
|
||||
+ .align = __alignof__(struct nf_conn_rtcache),
|
||||
+ .id = NF_CT_EXT_RTCACHE,
|
||||
+ .destroy = nf_conn_rtcache_destroy,
|
||||
+};
|
||||
+
|
||||
+static int __net_init rtcache_net_init(struct net *net)
|
||||
+{
|
||||
+ return nf_register_net_hooks(net, rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+}
|
||||
+
|
||||
+static void __net_exit rtcache_net_exit(struct net *net)
|
||||
+{
|
||||
+ /* remove hooks so no new connections get rtcache extension */
|
||||
+ nf_unregister_net_hooks(net, rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||
+}
|
||||
+
|
||||
+static struct pernet_operations rtcache_ops_net_ops = {
|
||||
+ .init = rtcache_net_init,
|
||||
+ .exit = rtcache_net_exit,
|
||||
+};
|
||||
+
|
||||
+static int __init nf_conntrack_rtcache_init(void)
|
||||
+{
|
||||
+ int ret = nf_ct_extend_register(&rtcache_extend);
|
||||
+
|
||||
+ if (ret < 0) {
|
||||
+ pr_err("nf_conntrack_rtcache: Unable to register extension\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = register_pernet_subsys(&rtcache_ops_net_ops);
|
||||
+ if (ret) {
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ ret = register_netdevice_notifier(&nf_rtcache_notifier);
|
||||
+ if (ret) {
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+ unregister_pernet_subsys(&rtcache_ops_net_ops);
|
||||
+ }
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static int nf_rtcache_ext_remove(struct nf_conn *ct, void *data)
|
||||
+{
|
||||
+ struct nf_conn_rtcache *rtc = nf_ct_rtcache_find(ct);
|
||||
+
|
||||
+ return rtc != NULL;
|
||||
+}
|
||||
+
|
||||
+static bool __exit nf_conntrack_rtcache_wait_for_dying(struct net *net)
|
||||
+{
|
||||
+ bool wait = false;
|
||||
+ int cpu;
|
||||
+
|
||||
+ for_each_possible_cpu(cpu) {
|
||||
+ struct nf_conntrack_tuple_hash *h;
|
||||
+ struct hlist_nulls_node *n;
|
||||
+ struct nf_conn *ct;
|
||||
+ struct ct_pcpu *pcpu = per_cpu_ptr(net->ct.pcpu_lists, cpu);
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ spin_lock_bh(&pcpu->lock);
|
||||
+
|
||||
+ hlist_nulls_for_each_entry(h, n, &pcpu->dying, hnnode) {
|
||||
+ ct = nf_ct_tuplehash_to_ctrack(h);
|
||||
+ if (nf_ct_rtcache_find(ct) != NULL) {
|
||||
+ wait = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ spin_unlock_bh(&pcpu->lock);
|
||||
+ rcu_read_unlock();
|
||||
+ }
|
||||
+
|
||||
+ return wait;
|
||||
+}
|
||||
+
|
||||
+static void __exit nf_conntrack_rtcache_fini(void)
|
||||
+{
|
||||
+ struct net *net;
|
||||
+ int count = 0;
|
||||
+
|
||||
+ synchronize_net();
|
||||
+
|
||||
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
|
||||
+ unregister_pernet_subsys(&rtcache_ops_net_ops);
|
||||
+
|
||||
+ synchronize_net();
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+
|
||||
+ /* zap all conntracks with rtcache extension */
|
||||
+ for_each_net(net)
|
||||
+ nf_ct_iterate_cleanup_net(net, nf_rtcache_ext_remove, NULL, 0, 0);
|
||||
+
|
||||
+ for_each_net(net) {
|
||||
+ /* .. and make sure they're gone from dying list, too */
|
||||
+ while (nf_conntrack_rtcache_wait_for_dying(net)) {
|
||||
+ msleep(200);
|
||||
+ WARN_ONCE(++count > 25, "Waiting for all rtcache conntracks to go away\n");
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ rtnl_unlock();
|
||||
+
|
||||
+ synchronize_net();
|
||||
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||
+}
|
||||
+module_init(nf_conntrack_rtcache_init);
|
||||
+module_exit(nf_conntrack_rtcache_fini);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+MODULE_AUTHOR("Florian Westphal <fw@strlen.de>");
|
||||
+MODULE_DESCRIPTION("Conntrack route cache extension");
|
||||
@ -0,0 +1,53 @@
|
||||
From afa0459daa7b08c7b2c879705b69d39b734a11d0 Mon Sep 17 00:00:00 2001
|
||||
From: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
Date: Fri, 15 Nov 2019 02:42:21 +0900
|
||||
Subject: [PATCH] modpost: add a helper to get data pointed by a symbol
|
||||
|
||||
When CONFIG_MODULE_REL_CRCS is enabled, the value of __crc_* is not
|
||||
an absolute value, but the address to the CRC data embedded in the
|
||||
.rodata section.
|
||||
|
||||
Getting the data pointed by the symbol value is somewhat complex.
|
||||
Split it out into a new helper, sym_get_data().
|
||||
|
||||
I will reuse it to refactor namespace_from_kstrtabns() in the next
|
||||
commit.
|
||||
|
||||
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
---
|
||||
scripts/mod/modpost.c | 17 +++++++++++++----
|
||||
1 file changed, 13 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/scripts/mod/modpost.c
|
||||
+++ b/scripts/mod/modpost.c
|
||||
@@ -312,6 +312,18 @@ static const char *sec_name(struct elf_i
|
||||
return sech_name(elf, &elf->sechdrs[secindex]);
|
||||
}
|
||||
|
||||
+static void *sym_get_data(const struct elf_info *info, const Elf_Sym *sym)
|
||||
+{
|
||||
+ Elf_Shdr *sechdr = &info->sechdrs[sym->st_shndx];
|
||||
+ unsigned long offset;
|
||||
+
|
||||
+ offset = sym->st_value;
|
||||
+ if (info->hdr->e_type != ET_REL)
|
||||
+ offset -= sechdr->sh_addr;
|
||||
+
|
||||
+ return (void *)info->hdr + sechdr->sh_offset + offset;
|
||||
+}
|
||||
+
|
||||
#define strstarts(str, prefix) (strncmp(str, prefix, strlen(prefix)) == 0)
|
||||
|
||||
static enum export export_from_secname(struct elf_info *elf, unsigned int sec)
|
||||
@@ -701,10 +713,7 @@ static void handle_modversions(struct mo
|
||||
unsigned int *crcp;
|
||||
|
||||
/* symbol points to the CRC in the ELF object */
|
||||
- crcp = (void *)info->hdr + sym->st_value +
|
||||
- info->sechdrs[sym->st_shndx].sh_offset -
|
||||
- (info->hdr->e_type != ET_REL ?
|
||||
- info->sechdrs[sym->st_shndx].sh_addr : 0);
|
||||
+ crcp = sym_get_data(info, sym);
|
||||
crc = TO_NATIVE(*crcp);
|
||||
}
|
||||
sym_update_crc(symname + strlen("__crc_"), mod, crc,
|
||||
@ -0,0 +1,62 @@
|
||||
From e84f9fbbece1585f45a03ccc11eeabe121cadc1b Mon Sep 17 00:00:00 2001
|
||||
From: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
Date: Fri, 15 Nov 2019 02:42:22 +0900
|
||||
Subject: [PATCH] modpost: refactor namespace_from_kstrtabns() to not hard-code
|
||||
section name
|
||||
|
||||
Currently, namespace_from_kstrtabns() relies on the fact that
|
||||
namespace strings are recorded in the __ksymtab_strings section.
|
||||
Actually, it is coded in include/linux/export.h, but modpost does
|
||||
not need to hard-code the section name.
|
||||
|
||||
Elf_Sym::st_shndx holds the index of the relevant section. Using it is
|
||||
a more portable way to get the namespace string.
|
||||
|
||||
Make namespace_from_kstrtabns() simply call sym_get_data(), and delete
|
||||
the info->ksymtab_strings .
|
||||
|
||||
While I was here, I added more 'const' qualifiers to pointers.
|
||||
|
||||
Signed-off-by: Masahiro Yamada <yamada.masahiro@socionext.com>
|
||||
---
|
||||
scripts/mod/modpost.c | 10 +++-------
|
||||
scripts/mod/modpost.h | 1 -
|
||||
2 files changed, 3 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/scripts/mod/modpost.c
|
||||
+++ b/scripts/mod/modpost.c
|
||||
@@ -360,10 +360,10 @@ static enum export export_from_sec(struc
|
||||
return export_unknown;
|
||||
}
|
||||
|
||||
-static const char *namespace_from_kstrtabns(struct elf_info *info,
|
||||
- Elf_Sym *kstrtabns)
|
||||
+static const char *namespace_from_kstrtabns(const struct elf_info *info,
|
||||
+ const Elf_Sym *sym)
|
||||
{
|
||||
- char *value = info->ksymtab_strings + kstrtabns->st_value;
|
||||
+ const char *value = sym_get_data(info, sym);
|
||||
return value[0] ? value : NULL;
|
||||
}
|
||||
|
||||
@@ -605,10 +605,6 @@ static int parse_elf(struct elf_info *in
|
||||
info->export_unused_gpl_sec = i;
|
||||
else if (strcmp(secname, "__ksymtab_gpl_future") == 0)
|
||||
info->export_gpl_future_sec = i;
|
||||
- else if (strcmp(secname, "__ksymtab_strings") == 0)
|
||||
- info->ksymtab_strings = (void *)hdr +
|
||||
- sechdrs[i].sh_offset -
|
||||
- sechdrs[i].sh_addr;
|
||||
|
||||
if (sechdrs[i].sh_type == SHT_SYMTAB) {
|
||||
unsigned int sh_link_idx;
|
||||
--- a/scripts/mod/modpost.h
|
||||
+++ b/scripts/mod/modpost.h
|
||||
@@ -143,7 +143,6 @@ struct elf_info {
|
||||
Elf_Section export_gpl_sec;
|
||||
Elf_Section export_unused_gpl_sec;
|
||||
Elf_Section export_gpl_future_sec;
|
||||
- char *ksymtab_strings;
|
||||
char *strtab;
|
||||
char *modinfo;
|
||||
unsigned int modinfo_len;
|
||||
@ -0,0 +1,60 @@
|
||||
From fb033c95c94ca1ee3d16e04ebdb85d65fb55fff8 Mon Sep 17 00:00:00 2001
|
||||
From: Ben Dooks <ben-linux@fluff.org>
|
||||
Date: Mon, 4 Nov 2019 18:15:15 +0100
|
||||
Subject: [PATCH] ARM: 8918/2: only build return_address() if needed
|
||||
|
||||
The system currently warns if the config conditions for
|
||||
building return_address in arch/arm/kernel/return_address.c
|
||||
are not met, leaving just an EXPORT_SYMBOL_GPL(return_address)
|
||||
of a function defined to be 'static linline'.
|
||||
This is a result of aeea3592a13b ("ARM: 8158/1: LLVMLinux: use static inline in ARM ftrace.h").
|
||||
|
||||
Since we're not going to build anything other than an exported
|
||||
symbol for something that is already being defined to be an
|
||||
inline-able return of NULL, just avoid building the code to
|
||||
remove the following warning:
|
||||
|
||||
Fixes: aeea3592a13b ("ARM: 8158/1: LLVMLinux: use static inline in ARM ftrace.h")
|
||||
Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
arch/arm/kernel/Makefile | 6 +++++-
|
||||
arch/arm/kernel/return_address.c | 4 ----
|
||||
2 files changed, 5 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/arch/arm/kernel/Makefile
|
||||
+++ b/arch/arm/kernel/Makefile
|
||||
@@ -17,10 +17,14 @@ CFLAGS_REMOVE_return_address.o = -pg
|
||||
# Object file lists.
|
||||
|
||||
obj-y := elf.o entry-common.o irq.o opcodes.o \
|
||||
- process.o ptrace.o reboot.o return_address.o \
|
||||
+ process.o ptrace.o reboot.o \
|
||||
setup.o signal.o sigreturn_codes.o \
|
||||
stacktrace.o sys_arm.o time.o traps.o
|
||||
|
||||
+ifneq ($(CONFIG_ARM_UNWIND),y)
|
||||
+obj-$(CONFIG_FRAME_POINTER) += return_address.o
|
||||
+endif
|
||||
+
|
||||
obj-$(CONFIG_ATAGS) += atags_parse.o
|
||||
obj-$(CONFIG_ATAGS_PROC) += atags_proc.o
|
||||
obj-$(CONFIG_DEPRECATED_PARAM_STRUCT) += atags_compat.o
|
||||
--- a/arch/arm/kernel/return_address.c
|
||||
+++ b/arch/arm/kernel/return_address.c
|
||||
@@ -7,8 +7,6 @@
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/ftrace.h>
|
||||
-
|
||||
-#if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND)
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <asm/stacktrace.h>
|
||||
@@ -53,6 +51,4 @@ void *return_address(unsigned int level)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-#endif /* if defined(CONFIG_FRAME_POINTER) && !defined(CONFIG_ARM_UNWIND) */
|
||||
-
|
||||
EXPORT_SYMBOL_GPL(return_address);
|
||||
@ -0,0 +1,134 @@
|
||||
From d96c3157f9ca177727fbad960fcf6f52f145f471 Mon Sep 17 00:00:00 2001
|
||||
From: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
Date: Thu, 9 Jan 2020 11:33:19 +0800
|
||||
Subject: [PATCH] MIPS: Exclude more dsemul code when CONFIG_MIPS_FP_SUPPORT=n
|
||||
|
||||
This furthers what commit 42b10815d559 ("MIPS: Don't compile math-emu
|
||||
when CONFIG_MIPS_FP_SUPPORT=n") has done
|
||||
|
||||
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
|
||||
---
|
||||
arch/mips/include/asm/processor.h | 12 ++++++------
|
||||
arch/mips/kernel/process.c | 10 ++++++++--
|
||||
arch/mips/kernel/vdso.c | 26 +++++++++++++++-----------
|
||||
3 files changed, 29 insertions(+), 19 deletions(-)
|
||||
|
||||
--- a/arch/mips/include/asm/processor.h
|
||||
+++ b/arch/mips/include/asm/processor.h
|
||||
@@ -253,13 +253,13 @@ struct thread_struct {
|
||||
#ifdef CONFIG_MIPS_FP_SUPPORT
|
||||
/* Saved fpu/fpu emulator stuff. */
|
||||
struct mips_fpu_struct fpu FPU_ALIGN;
|
||||
-#endif
|
||||
/* Assigned branch delay slot 'emulation' frame */
|
||||
atomic_t bd_emu_frame;
|
||||
/* PC of the branch from a branch delay slot 'emulation' */
|
||||
unsigned long bd_emu_branch_pc;
|
||||
/* PC to continue from following a branch delay slot 'emulation' */
|
||||
unsigned long bd_emu_cont_pc;
|
||||
+#endif
|
||||
#ifdef CONFIG_MIPS_MT_FPAFF
|
||||
/* Emulated instruction count */
|
||||
unsigned long emulated_fp;
|
||||
@@ -302,7 +302,11 @@ struct thread_struct {
|
||||
.fpr = {{{0,},},}, \
|
||||
.fcr31 = 0, \
|
||||
.msacsr = 0, \
|
||||
- },
|
||||
+ }, \
|
||||
+ /* Delay slot emulation */ \
|
||||
+ .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE), \
|
||||
+ .bd_emu_branch_pc = 0, \
|
||||
+ .bd_emu_cont_pc = 0,
|
||||
#else
|
||||
# define FPU_INIT
|
||||
#endif
|
||||
@@ -334,10 +338,6 @@ struct thread_struct {
|
||||
* FPU affinity state (null if not FPAFF) \
|
||||
*/ \
|
||||
FPAFF_INIT \
|
||||
- /* Delay slot emulation */ \
|
||||
- .bd_emu_frame = ATOMIC_INIT(BD_EMUFRAME_NONE), \
|
||||
- .bd_emu_branch_pc = 0, \
|
||||
- .bd_emu_cont_pc = 0, \
|
||||
/* \
|
||||
* Saved DSP stuff \
|
||||
*/ \
|
||||
--- a/arch/mips/kernel/process.c
|
||||
+++ b/arch/mips/kernel/process.c
|
||||
@@ -75,7 +75,9 @@ void start_thread(struct pt_regs * regs,
|
||||
lose_fpu(0);
|
||||
clear_thread_flag(TIF_MSA_CTX_LIVE);
|
||||
clear_used_math();
|
||||
+#ifdef CONFIG_MIPS_FP_SUPPORT
|
||||
atomic_set(¤t->thread.bd_emu_frame, BD_EMUFRAME_NONE);
|
||||
+#endif
|
||||
init_dsp();
|
||||
regs->cp0_epc = pc;
|
||||
regs->regs[29] = sp;
|
||||
@@ -176,7 +178,9 @@ int copy_thread_tls(unsigned long clone_
|
||||
clear_tsk_thread_flag(p, TIF_FPUBOUND);
|
||||
#endif /* CONFIG_MIPS_MT_FPAFF */
|
||||
|
||||
+#ifdef CONFIG_MIPS_FP_SUPPORT
|
||||
atomic_set(&p->thread.bd_emu_frame, BD_EMUFRAME_NONE);
|
||||
+#endif
|
||||
|
||||
if (clone_flags & CLONE_SETTLS)
|
||||
ti->tp_value = tls;
|
||||
@@ -650,8 +654,10 @@ unsigned long mips_stack_top(void)
|
||||
{
|
||||
unsigned long top = TASK_SIZE & PAGE_MASK;
|
||||
|
||||
- /* One page for branch delay slot "emulation" */
|
||||
- top -= PAGE_SIZE;
|
||||
+ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
|
||||
+ /* One page for branch delay slot "emulation" */
|
||||
+ top -= PAGE_SIZE;
|
||||
+ }
|
||||
|
||||
/* Space for the VDSO, data page & GIC user page */
|
||||
top -= PAGE_ALIGN(current->thread.abi->vdso->size);
|
||||
--- a/arch/mips/kernel/vdso.c
|
||||
+++ b/arch/mips/kernel/vdso.c
|
||||
@@ -71,10 +71,12 @@ subsys_initcall(init_vdso);
|
||||
|
||||
static unsigned long vdso_base(void)
|
||||
{
|
||||
- unsigned long base;
|
||||
+ unsigned long base = STACK_TOP;
|
||||
|
||||
- /* Skip the delay slot emulation page */
|
||||
- base = STACK_TOP + PAGE_SIZE;
|
||||
+ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
|
||||
+ /* Skip the delay slot emulation page */
|
||||
+ base += PAGE_SIZE;
|
||||
+ }
|
||||
|
||||
if (current->flags & PF_RANDOMIZE) {
|
||||
base += get_random_int() & (VDSO_RANDOMIZE_SIZE - 1);
|
||||
@@ -95,14 +97,16 @@ int arch_setup_additional_pages(struct l
|
||||
if (down_write_killable(&mm->mmap_sem))
|
||||
return -EINTR;
|
||||
|
||||
- /* Map delay slot emulation page */
|
||||
- base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
|
||||
- VM_READ | VM_EXEC |
|
||||
- VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
|
||||
- 0, NULL);
|
||||
- if (IS_ERR_VALUE(base)) {
|
||||
- ret = base;
|
||||
- goto out;
|
||||
+ if (IS_ENABLED(CONFIG_MIPS_FP_SUPPORT)) {
|
||||
+ /* Map delay slot emulation page */
|
||||
+ base = mmap_region(NULL, STACK_TOP, PAGE_SIZE,
|
||||
+ VM_READ | VM_EXEC |
|
||||
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
|
||||
+ 0, NULL);
|
||||
+ if (IS_ERR_VALUE(base)) {
|
||||
+ ret = base;
|
||||
+ goto out;
|
||||
+ }
|
||||
}
|
||||
|
||||
/*
|
||||
@ -0,0 +1,99 @@
|
||||
From: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
Date: Thu, 25 Jan 2018 12:58:55 +0100
|
||||
Subject: [PATCH] netfilter: nft_flow_offload: handle netdevice events from
|
||||
nf_flow_table
|
||||
|
||||
Move the code that deals with device events to the core.
|
||||
|
||||
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -529,5 +529,35 @@ void nf_flow_table_free(struct nf_flowta
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nf_flow_table_free);
|
||||
|
||||
+static int nf_flow_table_netdev_event(struct notifier_block *this,
|
||||
+ unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+
|
||||
+ if (event != NETDEV_DOWN)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ nf_flow_table_cleanup(dev);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block flow_offload_netdev_notifier = {
|
||||
+ .notifier_call = nf_flow_table_netdev_event,
|
||||
+};
|
||||
+
|
||||
+static int __init nf_flow_table_module_init(void)
|
||||
+{
|
||||
+ return register_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
+}
|
||||
+
|
||||
+static void __exit nf_flow_table_module_exit(void)
|
||||
+{
|
||||
+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
+}
|
||||
+
|
||||
+module_init(nf_flow_table_module_init);
|
||||
+module_exit(nf_flow_table_module_exit);
|
||||
+
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_AUTHOR("Pablo Neira Ayuso <pablo@netfilter.org>");
|
||||
--- a/net/netfilter/nft_flow_offload.c
|
||||
+++ b/net/netfilter/nft_flow_offload.c
|
||||
@@ -234,47 +234,14 @@ static struct nft_expr_type nft_flow_off
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
-static int flow_offload_netdev_event(struct notifier_block *this,
|
||||
- unsigned long event, void *ptr)
|
||||
-{
|
||||
- struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
-
|
||||
- if (event != NETDEV_DOWN)
|
||||
- return NOTIFY_DONE;
|
||||
-
|
||||
- nf_flow_table_cleanup(dev);
|
||||
-
|
||||
- return NOTIFY_DONE;
|
||||
-}
|
||||
-
|
||||
-static struct notifier_block flow_offload_netdev_notifier = {
|
||||
- .notifier_call = flow_offload_netdev_event,
|
||||
-};
|
||||
-
|
||||
static int __init nft_flow_offload_module_init(void)
|
||||
{
|
||||
- int err;
|
||||
-
|
||||
- err = register_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
- if (err)
|
||||
- goto err;
|
||||
-
|
||||
- err = nft_register_expr(&nft_flow_offload_type);
|
||||
- if (err < 0)
|
||||
- goto register_expr;
|
||||
-
|
||||
- return 0;
|
||||
-
|
||||
-register_expr:
|
||||
- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
-err:
|
||||
- return err;
|
||||
+ return nft_register_expr(&nft_flow_offload_type);
|
||||
}
|
||||
|
||||
static void __exit nft_flow_offload_module_exit(void)
|
||||
{
|
||||
nft_unregister_expr(&nft_flow_offload_type);
|
||||
- unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
}
|
||||
|
||||
module_init(nft_flow_offload_module_init);
|
||||
@ -0,0 +1,114 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 13 Jun 2018 12:33:39 +0200
|
||||
Subject: [PATCH] netfilter: nf_flow_table: fix offloaded connection timeout
|
||||
corner case
|
||||
|
||||
The full teardown of offloaded flows is deferred to a gc work item,
|
||||
however processing of packets by netfilter needs to happen immediately
|
||||
after a teardown is requested, because the conntrack state needs to be
|
||||
fixed up.
|
||||
|
||||
Since the IPS_OFFLOAD_BIT is still kept until the teardown is complete,
|
||||
the netfilter conntrack gc can accidentally bump the timeout of a
|
||||
connection where offload was just stopped, causing a conntrack entry
|
||||
leak.
|
||||
|
||||
Fix this by moving the conntrack timeout bumping from conntrack core to
|
||||
the nf_flow_offload and add a check to prevent bogus timeout bumps.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nf_conntrack_core.c
|
||||
+++ b/net/netfilter/nf_conntrack_core.c
|
||||
@@ -1206,18 +1206,6 @@ static bool gc_worker_can_early_drop(con
|
||||
return false;
|
||||
}
|
||||
|
||||
-#define DAY (86400 * HZ)
|
||||
-
|
||||
-/* Set an arbitrary timeout large enough not to ever expire, this save
|
||||
- * us a check for the IPS_OFFLOAD_BIT from the packet path via
|
||||
- * nf_ct_is_expired().
|
||||
- */
|
||||
-static void nf_ct_offload_timeout(struct nf_conn *ct)
|
||||
-{
|
||||
- if (nf_ct_expires(ct) < DAY / 2)
|
||||
- ct->timeout = nfct_time_stamp + DAY;
|
||||
-}
|
||||
-
|
||||
static void gc_worker(struct work_struct *work)
|
||||
{
|
||||
unsigned int min_interval = max(HZ / GC_MAX_BUCKETS_DIV, 1u);
|
||||
@@ -1254,10 +1242,8 @@ static void gc_worker(struct work_struct
|
||||
tmp = nf_ct_tuplehash_to_ctrack(h);
|
||||
|
||||
scanned++;
|
||||
- if (test_bit(IPS_OFFLOAD_BIT, &tmp->status)) {
|
||||
- nf_ct_offload_timeout(tmp);
|
||||
+ if (test_bit(IPS_OFFLOAD_BIT, &tmp->status))
|
||||
continue;
|
||||
- }
|
||||
|
||||
if (nf_ct_is_expired(tmp)) {
|
||||
nf_ct_gc_expired(tmp);
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -198,10 +198,29 @@ static const struct rhashtable_params nf
|
||||
.automatic_shrinking = true,
|
||||
};
|
||||
|
||||
+#define DAY (86400 * HZ)
|
||||
+
|
||||
+/* Set an arbitrary timeout large enough not to ever expire, this save
|
||||
+ * us a check for the IPS_OFFLOAD_BIT from the packet path via
|
||||
+ * nf_ct_is_expired().
|
||||
+ */
|
||||
+static void nf_ct_offload_timeout(struct flow_offload *flow)
|
||||
+{
|
||||
+ struct flow_offload_entry *entry;
|
||||
+ struct nf_conn *ct;
|
||||
+
|
||||
+ entry = container_of(flow, struct flow_offload_entry, flow);
|
||||
+ ct = entry->ct;
|
||||
+
|
||||
+ if (nf_ct_expires(ct) < DAY / 2)
|
||||
+ ct->timeout = nfct_time_stamp + DAY;
|
||||
+}
|
||||
+
|
||||
int flow_offload_add(struct nf_flowtable *flow_table, struct flow_offload *flow)
|
||||
{
|
||||
int err;
|
||||
|
||||
+ nf_ct_offload_timeout(flow);
|
||||
flow->timeout = (u32)jiffies + NF_FLOW_TIMEOUT;
|
||||
|
||||
err = rhashtable_insert_fast(&flow_table->rhashtable,
|
||||
@@ -304,6 +323,7 @@ nf_flow_table_iterate(struct nf_flowtabl
|
||||
rhashtable_walk_start(&hti);
|
||||
|
||||
while ((tuplehash = rhashtable_walk_next(&hti))) {
|
||||
+
|
||||
if (IS_ERR(tuplehash)) {
|
||||
if (PTR_ERR(tuplehash) != -EAGAIN) {
|
||||
err = PTR_ERR(tuplehash);
|
||||
@@ -328,10 +348,17 @@ static void nf_flow_offload_gc_step(stru
|
||||
{
|
||||
struct nf_flowtable *flow_table = data;
|
||||
struct flow_offload_entry *e;
|
||||
+ bool teardown;
|
||||
|
||||
e = container_of(flow, struct flow_offload_entry, flow);
|
||||
- if (nf_flow_has_expired(flow) || nf_ct_is_dying(e->ct) ||
|
||||
- (flow->flags & (FLOW_OFFLOAD_DYING | FLOW_OFFLOAD_TEARDOWN)))
|
||||
+
|
||||
+ teardown = flow->flags & (FLOW_OFFLOAD_DYING |
|
||||
+ FLOW_OFFLOAD_TEARDOWN);
|
||||
+
|
||||
+ if (!teardown)
|
||||
+ nf_ct_offload_timeout(flow);
|
||||
+
|
||||
+ if (nf_flow_has_expired(flow) || teardown)
|
||||
flow_offload_del(flow_table, flow);
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Thu, 14 Jun 2018 11:20:09 +0200
|
||||
Subject: [PATCH] netfilter: nf_flow_table: fix up ct state of flows after
|
||||
timeout
|
||||
|
||||
If a connection simply times out instead of being torn down, it is left
|
||||
active with a long timeout. Fix this by calling flow_offload_fixup_ct_state
|
||||
here as well.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -268,6 +268,9 @@ static void flow_offload_del(struct nf_f
|
||||
else if (flow->flags & FLOW_OFFLOAD_TEARDOWN)
|
||||
flow_offload_fixup_ct_timeout(e->ct);
|
||||
|
||||
+ if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
|
||||
+ flow_offload_fixup_ct_state(e->ct);
|
||||
+
|
||||
flow_offload_free(flow);
|
||||
}
|
||||
|
||||
@ -0,0 +1,28 @@
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Mon, 9 Mar 2020 08:30:19 +0100
|
||||
Subject: [PATCH] mtd: fix calculating partition end address
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This fixes check for partitions that don't start at beginning of their
|
||||
parents. Missing partition's offset in formula could result in forcing
|
||||
read-only incorrectly.
|
||||
|
||||
Fixes: 6750f61a13a0 ("mtd: improve calculating partition boundaries when checking for alignment")
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -524,7 +524,7 @@ static struct mtd_part *allocate_partiti
|
||||
part->name);
|
||||
}
|
||||
|
||||
- tmp = part_absolute_offset(parent) + slave->mtd.size;
|
||||
+ tmp = part_absolute_offset(parent) + slave->offset + slave->mtd.size;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
|
||||
slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||
@ -0,0 +1,179 @@
|
||||
From 4054955f0da08c81d42220cb445820d474f1ac92 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sat, 14 Sep 2019 14:21:22 +0100
|
||||
Subject: [PATCH 614/660] net: sfp: move fwnode parsing into sfp-bus layer
|
||||
|
||||
Rather than parsing the sfp firmware node in phylink, parse it in the
|
||||
sfp-bus code, so we can re-use this code for PHYs without having to
|
||||
duplicate the parsing.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 21 ++++---------
|
||||
drivers/net/phy/sfp-bus.c | 65 +++++++++++++++++++++++++--------------
|
||||
include/linux/sfp.h | 10 +++---
|
||||
3 files changed, 53 insertions(+), 43 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -565,26 +565,17 @@ static const struct sfp_upstream_ops sfp
|
||||
static int phylink_register_sfp(struct phylink *pl,
|
||||
struct fwnode_handle *fwnode)
|
||||
{
|
||||
- struct fwnode_reference_args ref;
|
||||
+ struct sfp_bus *bus;
|
||||
int ret;
|
||||
|
||||
- if (!fwnode)
|
||||
- return 0;
|
||||
-
|
||||
- ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
|
||||
- 0, 0, &ref);
|
||||
- if (ret < 0) {
|
||||
- if (ret == -ENOENT)
|
||||
- return 0;
|
||||
-
|
||||
- phylink_err(pl, "unable to parse \"sfp\" node: %d\n",
|
||||
- ret);
|
||||
+ bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
|
||||
+ if (IS_ERR(bus)) {
|
||||
+ ret = PTR_ERR(bus);
|
||||
+ phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
- pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
|
||||
- if (!pl->sfp_bus)
|
||||
- return -ENOMEM;
|
||||
+ pl->sfp_bus = bus;
|
||||
|
||||
return 0;
|
||||
}
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/phylink.h>
|
||||
+#include <linux/property.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
@@ -445,45 +446,63 @@ static void sfp_upstream_clear(struct sf
|
||||
}
|
||||
|
||||
/**
|
||||
- * sfp_register_upstream() - Register the neighbouring device
|
||||
- * @fwnode: firmware node for the SFP bus
|
||||
+ * sfp_register_upstream_node() - parse and register the neighbouring device
|
||||
+ * @fwnode: firmware node for the parent device (MAC or PHY)
|
||||
* @upstream: the upstream private data
|
||||
* @ops: the upstream's &struct sfp_upstream_ops
|
||||
*
|
||||
- * Register the upstream device (eg, PHY) with the SFP bus. MAC drivers
|
||||
- * should use phylink, which will call this function for them. Returns
|
||||
- * a pointer to the allocated &struct sfp_bus.
|
||||
+ * Parse the parent device's firmware node for a SFP bus, and register the
|
||||
+ * SFP bus using sfp_register_upstream().
|
||||
*
|
||||
- * On error, returns %NULL.
|
||||
+ * Returns: on success, a pointer to the sfp_bus structure,
|
||||
+ * %NULL if no SFP is specified,
|
||||
+ * on failure, an error pointer value:
|
||||
+ * corresponding to the errors detailed for
|
||||
+ * fwnode_property_get_reference_args().
|
||||
+ * %-ENOMEM if we failed to allocate the bus.
|
||||
+ * an error from the upstream's connect_phy() method.
|
||||
*/
|
||||
-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
|
||||
- void *upstream,
|
||||
- const struct sfp_upstream_ops *ops)
|
||||
-{
|
||||
- struct sfp_bus *bus = sfp_bus_get(fwnode);
|
||||
- int ret = 0;
|
||||
-
|
||||
- if (bus) {
|
||||
- rtnl_lock();
|
||||
- bus->upstream_ops = ops;
|
||||
- bus->upstream = upstream;
|
||||
+struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
|
||||
+ void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops)
|
||||
+{
|
||||
+ struct fwnode_reference_args ref;
|
||||
+ struct sfp_bus *bus;
|
||||
+ int ret;
|
||||
|
||||
- if (bus->sfp) {
|
||||
- ret = sfp_register_bus(bus);
|
||||
- if (ret)
|
||||
- sfp_upstream_clear(bus);
|
||||
- }
|
||||
- rtnl_unlock();
|
||||
+ ret = fwnode_property_get_reference_args(fwnode, "sfp", NULL,
|
||||
+ 0, 0, &ref);
|
||||
+ if (ret == -ENOENT)
|
||||
+ return NULL;
|
||||
+ else if (ret < 0)
|
||||
+ return ERR_PTR(ret);
|
||||
+
|
||||
+ bus = sfp_bus_get(ref.fwnode);
|
||||
+ fwnode_handle_put(ref.fwnode);
|
||||
+ if (!bus)
|
||||
+ return ERR_PTR(-ENOMEM);
|
||||
+
|
||||
+ rtnl_lock();
|
||||
+ bus->upstream_ops = ops;
|
||||
+ bus->upstream = upstream;
|
||||
+
|
||||
+ if (bus->sfp) {
|
||||
+ ret = sfp_register_bus(bus);
|
||||
+ if (ret)
|
||||
+ sfp_upstream_clear(bus);
|
||||
+ } else {
|
||||
+ ret = 0;
|
||||
}
|
||||
+ rtnl_unlock();
|
||||
|
||||
if (ret) {
|
||||
sfp_bus_put(bus);
|
||||
- bus = NULL;
|
||||
+ bus = ERR_PTR(ret);
|
||||
}
|
||||
|
||||
return bus;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(sfp_register_upstream);
|
||||
+EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
|
||||
|
||||
/**
|
||||
* sfp_unregister_upstream() - Unregister sfp bus
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -508,9 +508,9 @@ int sfp_get_module_eeprom(struct sfp_bus
|
||||
u8 *data);
|
||||
void sfp_upstream_start(struct sfp_bus *bus);
|
||||
void sfp_upstream_stop(struct sfp_bus *bus);
|
||||
-struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
|
||||
- void *upstream,
|
||||
- const struct sfp_upstream_ops *ops);
|
||||
+struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
|
||||
+ void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops);
|
||||
void sfp_unregister_upstream(struct sfp_bus *bus);
|
||||
#else
|
||||
static inline int sfp_parse_port(struct sfp_bus *bus,
|
||||
@@ -553,11 +553,11 @@ static inline void sfp_upstream_stop(str
|
||||
{
|
||||
}
|
||||
|
||||
-static inline struct sfp_bus *sfp_register_upstream(
|
||||
+static inline struct sfp_bus *sfp_register_upstream_node(
|
||||
struct fwnode_handle *fwnode, void *upstream,
|
||||
const struct sfp_upstream_ops *ops)
|
||||
{
|
||||
- return (struct sfp_bus *)-1;
|
||||
+ return NULL;
|
||||
}
|
||||
|
||||
static inline void sfp_unregister_upstream(struct sfp_bus *bus)
|
||||
@ -0,0 +1,254 @@
|
||||
From 863b5b6941f9f43b924393b6ba2b36647e7dee42 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 7 Nov 2019 17:06:08 +0000
|
||||
Subject: [PATCH 615/660] net: sfp: rework upstream interface
|
||||
|
||||
The current upstream interface is an all-or-nothing, which is
|
||||
sub-optimal for future changes, as it doesn't allow the upstream driver
|
||||
to prepare for the SFP module becoming available, as it is at boot.
|
||||
|
||||
Switch to a find-sfp-bus, add-upstream, del-upstream, put-sfp-bus
|
||||
interface structure instead, which allows the upstream driver to
|
||||
prepare for a module being available as soon as add-upstream is called.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 10 +++--
|
||||
drivers/net/phy/sfp-bus.c | 92 +++++++++++++++++++++++++++------------
|
||||
include/linux/sfp.h | 25 +++++++----
|
||||
3 files changed, 88 insertions(+), 39 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -568,7 +568,7 @@ static int phylink_register_sfp(struct p
|
||||
struct sfp_bus *bus;
|
||||
int ret;
|
||||
|
||||
- bus = sfp_register_upstream_node(fwnode, pl, &sfp_phylink_ops);
|
||||
+ bus = sfp_bus_find_fwnode(fwnode);
|
||||
if (IS_ERR(bus)) {
|
||||
ret = PTR_ERR(bus);
|
||||
phylink_err(pl, "unable to attach SFP bus: %d\n", ret);
|
||||
@@ -577,7 +577,10 @@ static int phylink_register_sfp(struct p
|
||||
|
||||
pl->sfp_bus = bus;
|
||||
|
||||
- return 0;
|
||||
+ ret = sfp_bus_add_upstream(bus, pl, &sfp_phylink_ops);
|
||||
+ sfp_bus_put(bus);
|
||||
+
|
||||
+ return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -675,8 +678,7 @@ EXPORT_SYMBOL_GPL(phylink_create);
|
||||
*/
|
||||
void phylink_destroy(struct phylink *pl)
|
||||
{
|
||||
- if (pl->sfp_bus)
|
||||
- sfp_unregister_upstream(pl->sfp_bus);
|
||||
+ sfp_bus_del_upstream(pl->sfp_bus);
|
||||
if (pl->link_gpio)
|
||||
gpiod_put(pl->link_gpio);
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -329,10 +329,19 @@ static void sfp_bus_release(struct kref
|
||||
kfree(bus);
|
||||
}
|
||||
|
||||
-static void sfp_bus_put(struct sfp_bus *bus)
|
||||
+/**
|
||||
+ * sfp_bus_put() - put a reference on the &struct sfp_bus
|
||||
+ * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
|
||||
+ *
|
||||
+ * Put a reference on the &struct sfp_bus and free the underlying structure
|
||||
+ * if this was the last reference.
|
||||
+ */
|
||||
+void sfp_bus_put(struct sfp_bus *bus)
|
||||
{
|
||||
- kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
|
||||
+ if (bus)
|
||||
+ kref_put_mutex(&bus->kref, sfp_bus_release, &sfp_mutex);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(sfp_bus_put);
|
||||
|
||||
static int sfp_register_bus(struct sfp_bus *bus)
|
||||
{
|
||||
@@ -348,11 +357,11 @@ static int sfp_register_bus(struct sfp_b
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
+ bus->registered = true;
|
||||
bus->socket_ops->attach(bus->sfp);
|
||||
if (bus->started)
|
||||
bus->socket_ops->start(bus->sfp);
|
||||
bus->upstream_ops->attach(bus->upstream, bus);
|
||||
- bus->registered = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -446,13 +455,12 @@ static void sfp_upstream_clear(struct sf
|
||||
}
|
||||
|
||||
/**
|
||||
- * sfp_register_upstream_node() - parse and register the neighbouring device
|
||||
+ * sfp_bus_find_fwnode() - parse and locate the SFP bus from fwnode
|
||||
* @fwnode: firmware node for the parent device (MAC or PHY)
|
||||
- * @upstream: the upstream private data
|
||||
- * @ops: the upstream's &struct sfp_upstream_ops
|
||||
*
|
||||
- * Parse the parent device's firmware node for a SFP bus, and register the
|
||||
- * SFP bus using sfp_register_upstream().
|
||||
+ * Parse the parent device's firmware node for a SFP bus, and locate
|
||||
+ * the sfp_bus structure, incrementing its reference count. This must
|
||||
+ * be put via sfp_bus_put() when done.
|
||||
*
|
||||
* Returns: on success, a pointer to the sfp_bus structure,
|
||||
* %NULL if no SFP is specified,
|
||||
@@ -462,9 +470,7 @@ static void sfp_upstream_clear(struct sf
|
||||
* %-ENOMEM if we failed to allocate the bus.
|
||||
* an error from the upstream's connect_phy() method.
|
||||
*/
|
||||
-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
|
||||
- void *upstream,
|
||||
- const struct sfp_upstream_ops *ops)
|
||||
+struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
struct fwnode_reference_args ref;
|
||||
struct sfp_bus *bus;
|
||||
@@ -482,7 +488,39 @@ struct sfp_bus *sfp_register_upstream_no
|
||||
if (!bus)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
+ return bus;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(sfp_bus_find_fwnode);
|
||||
+
|
||||
+/**
|
||||
+ * sfp_bus_add_upstream() - parse and register the neighbouring device
|
||||
+ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
|
||||
+ * @upstream: the upstream private data
|
||||
+ * @ops: the upstream's &struct sfp_upstream_ops
|
||||
+ *
|
||||
+ * Add upstream driver for the SFP bus, and if the bus is complete, register
|
||||
+ * the SFP bus using sfp_register_upstream(). This takes a reference on the
|
||||
+ * bus, so it is safe to put the bus after this call.
|
||||
+ *
|
||||
+ * Returns: on success, a pointer to the sfp_bus structure,
|
||||
+ * %NULL if no SFP is specified,
|
||||
+ * on failure, an error pointer value:
|
||||
+ * corresponding to the errors detailed for
|
||||
+ * fwnode_property_get_reference_args().
|
||||
+ * %-ENOMEM if we failed to allocate the bus.
|
||||
+ * an error from the upstream's connect_phy() method.
|
||||
+ */
|
||||
+int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ /* If no bus, return success */
|
||||
+ if (!bus)
|
||||
+ return 0;
|
||||
+
|
||||
rtnl_lock();
|
||||
+ kref_get(&bus->kref);
|
||||
bus->upstream_ops = ops;
|
||||
bus->upstream = upstream;
|
||||
|
||||
@@ -495,33 +533,33 @@ struct sfp_bus *sfp_register_upstream_no
|
||||
}
|
||||
rtnl_unlock();
|
||||
|
||||
- if (ret) {
|
||||
+ if (ret)
|
||||
sfp_bus_put(bus);
|
||||
- bus = ERR_PTR(ret);
|
||||
- }
|
||||
|
||||
- return bus;
|
||||
+ return ret;
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(sfp_register_upstream_node);
|
||||
+EXPORT_SYMBOL_GPL(sfp_bus_add_upstream);
|
||||
|
||||
/**
|
||||
- * sfp_unregister_upstream() - Unregister sfp bus
|
||||
+ * sfp_bus_del_upstream() - Delete a sfp bus
|
||||
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
*
|
||||
- * Unregister a previously registered upstream connection for the SFP
|
||||
- * module. @bus is returned from sfp_register_upstream().
|
||||
+ * Delete a previously registered upstream connection for the SFP
|
||||
+ * module. @bus should have been added by sfp_bus_add_upstream().
|
||||
*/
|
||||
-void sfp_unregister_upstream(struct sfp_bus *bus)
|
||||
+void sfp_bus_del_upstream(struct sfp_bus *bus)
|
||||
{
|
||||
- rtnl_lock();
|
||||
- if (bus->sfp)
|
||||
- sfp_unregister_bus(bus);
|
||||
- sfp_upstream_clear(bus);
|
||||
- rtnl_unlock();
|
||||
+ if (bus) {
|
||||
+ rtnl_lock();
|
||||
+ if (bus->sfp)
|
||||
+ sfp_unregister_bus(bus);
|
||||
+ sfp_upstream_clear(bus);
|
||||
+ rtnl_unlock();
|
||||
|
||||
- sfp_bus_put(bus);
|
||||
+ sfp_bus_put(bus);
|
||||
+ }
|
||||
}
|
||||
-EXPORT_SYMBOL_GPL(sfp_unregister_upstream);
|
||||
+EXPORT_SYMBOL_GPL(sfp_bus_del_upstream);
|
||||
|
||||
/* Socket driver entry points */
|
||||
int sfp_add_phy(struct sfp_bus *bus, struct phy_device *phydev)
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -508,10 +508,11 @@ int sfp_get_module_eeprom(struct sfp_bus
|
||||
u8 *data);
|
||||
void sfp_upstream_start(struct sfp_bus *bus);
|
||||
void sfp_upstream_stop(struct sfp_bus *bus);
|
||||
-struct sfp_bus *sfp_register_upstream_node(struct fwnode_handle *fwnode,
|
||||
- void *upstream,
|
||||
- const struct sfp_upstream_ops *ops);
|
||||
-void sfp_unregister_upstream(struct sfp_bus *bus);
|
||||
+void sfp_bus_put(struct sfp_bus *bus);
|
||||
+struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode);
|
||||
+int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops);
|
||||
+void sfp_bus_del_upstream(struct sfp_bus *bus);
|
||||
#else
|
||||
static inline int sfp_parse_port(struct sfp_bus *bus,
|
||||
const struct sfp_eeprom_id *id,
|
||||
@@ -553,14 +554,22 @@ static inline void sfp_upstream_stop(str
|
||||
{
|
||||
}
|
||||
|
||||
-static inline struct sfp_bus *sfp_register_upstream_node(
|
||||
- struct fwnode_handle *fwnode, void *upstream,
|
||||
- const struct sfp_upstream_ops *ops)
|
||||
+static inline void sfp_bus_put(struct sfp_bus *bus)
|
||||
+{
|
||||
+}
|
||||
+
|
||||
+static inline struct sfp_bus *sfp_bus_find_fwnode(struct fwnode_handle *fwnode)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static inline void sfp_unregister_upstream(struct sfp_bus *bus)
|
||||
+static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline void sfp_bus_del_upstream(struct sfp_bus *bus)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,27 @@
|
||||
From ea7bfd81921827d334c2a23bd11ef0e4e2abafd2 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sat, 9 Nov 2019 08:13:50 +0000
|
||||
Subject: [PATCH 616/660] net: sfp: fix sfp_bus_put() kernel documentation
|
||||
|
||||
The kbuild test robot found a problem with htmldocs with the recent
|
||||
change to the SFP interfaces. Fix the kernel documentation for
|
||||
sfp_bus_put() which was missing an '@' before the argument name
|
||||
description.
|
||||
|
||||
Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -331,7 +331,7 @@ static void sfp_bus_release(struct kref
|
||||
|
||||
/**
|
||||
* sfp_bus_put() - put a reference on the &struct sfp_bus
|
||||
- * bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
|
||||
+ * @bus: the &struct sfp_bus found via sfp_bus_find_fwnode()
|
||||
*
|
||||
* Put a reference on the &struct sfp_bus and free the underlying structure
|
||||
* if this was the last reference.
|
||||
@ -0,0 +1,27 @@
|
||||
From f76d84cd85f8bd3f083495f7ca723822cba8abc9 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Mon, 11 Nov 2019 10:23:35 +0000
|
||||
Subject: [PATCH 617/660] net: sfp: fix sfp_bus_add_upstream() warning
|
||||
|
||||
When building with SFP disabled, the stub for sfp_bus_add_upstream()
|
||||
missed "inline". Add it.
|
||||
|
||||
Fixes: 727b3668b730 ("net: sfp: rework upstream interface")
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
include/linux/sfp.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -563,8 +563,8 @@ static inline struct sfp_bus *sfp_bus_fi
|
||||
return NULL;
|
||||
}
|
||||
|
||||
-static int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||
- const struct sfp_upstream_ops *ops)
|
||||
+static inline int sfp_bus_add_upstream(struct sfp_bus *bus, void *upstream,
|
||||
+ const struct sfp_upstream_ops *ops)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,124 @@
|
||||
From b9d6ed5cdb67533feda7f221eb06f2f9f1ff5047 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 11 Oct 2019 19:33:58 +0100
|
||||
Subject: [PATCH 618/660] net: sfp: move sfp sub-state machines into separate
|
||||
functions
|
||||
|
||||
Move the SFP sub-state machines out of the main state machine function,
|
||||
in preparation for it doing a bit more with the device state. By doing
|
||||
so, we ensure that our debug after the main state machine is always
|
||||
printed.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 74 +++++++++++++++++++++++++------------------
|
||||
1 file changed, 43 insertions(+), 31 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1544,19 +1544,34 @@ static void sfp_sm_mod_remove(struct sfp
|
||||
dev_info(sfp->dev, "module removed\n");
|
||||
}
|
||||
|
||||
-static void sfp_sm_event(struct sfp *sfp, unsigned int event)
|
||||
+/* This state machine tracks the netdev up/down state */
|
||||
+static void sfp_sm_device(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
- mutex_lock(&sfp->sm_mutex);
|
||||
+ switch (sfp->sm_dev_state) {
|
||||
+ default:
|
||||
+ if (event == SFP_E_DEV_UP)
|
||||
+ sfp->sm_dev_state = SFP_DEV_UP;
|
||||
+ break;
|
||||
|
||||
- dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
|
||||
- mod_state_to_str(sfp->sm_mod_state),
|
||||
- dev_state_to_str(sfp->sm_dev_state),
|
||||
- sm_state_to_str(sfp->sm_state),
|
||||
- event_to_str(event));
|
||||
+ case SFP_DEV_UP:
|
||||
+ if (event == SFP_E_DEV_DOWN) {
|
||||
+ /* If the module has a PHY, avoid raising TX disable
|
||||
+ * as this resets the PHY. Otherwise, raise it to
|
||||
+ * turn the laser off.
|
||||
+ */
|
||||
+ if (!sfp->mod_phy)
|
||||
+ sfp_module_tx_disable(sfp);
|
||||
+ sfp->sm_dev_state = SFP_DEV_DOWN;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
|
||||
- /* This state machine tracks the insert/remove state of
|
||||
- * the module, and handles probing the on-board EEPROM.
|
||||
- */
|
||||
+/* This state machine tracks the insert/remove state of
|
||||
+ * the module, and handles probing the on-board EEPROM.
|
||||
+ */
|
||||
+static void sfp_sm_module(struct sfp *sfp, unsigned int event)
|
||||
+{
|
||||
switch (sfp->sm_mod_state) {
|
||||
default:
|
||||
if (event == SFP_E_INSERT && sfp->attached) {
|
||||
@@ -1596,27 +1611,10 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
}
|
||||
break;
|
||||
}
|
||||
+}
|
||||
|
||||
- /* This state machine tracks the netdev up/down state */
|
||||
- switch (sfp->sm_dev_state) {
|
||||
- default:
|
||||
- if (event == SFP_E_DEV_UP)
|
||||
- sfp->sm_dev_state = SFP_DEV_UP;
|
||||
- break;
|
||||
-
|
||||
- case SFP_DEV_UP:
|
||||
- if (event == SFP_E_DEV_DOWN) {
|
||||
- /* If the module has a PHY, avoid raising TX disable
|
||||
- * as this resets the PHY. Otherwise, raise it to
|
||||
- * turn the laser off.
|
||||
- */
|
||||
- if (!sfp->mod_phy)
|
||||
- sfp_module_tx_disable(sfp);
|
||||
- sfp->sm_dev_state = SFP_DEV_DOWN;
|
||||
- }
|
||||
- break;
|
||||
- }
|
||||
-
|
||||
+static void sfp_sm_main(struct sfp *sfp, unsigned int event)
|
||||
+{
|
||||
/* Some events are global */
|
||||
if (sfp->sm_state != SFP_S_DOWN &&
|
||||
(sfp->sm_mod_state != SFP_MOD_PRESENT ||
|
||||
@@ -1627,7 +1625,6 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
if (sfp->mod_phy)
|
||||
sfp_sm_phy_detach(sfp);
|
||||
sfp_sm_next(sfp, SFP_S_DOWN, 0);
|
||||
- mutex_unlock(&sfp->sm_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1682,6 +1679,21 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
case SFP_S_TX_DISABLE:
|
||||
break;
|
||||
}
|
||||
+}
|
||||
+
|
||||
+static void sfp_sm_event(struct sfp *sfp, unsigned int event)
|
||||
+{
|
||||
+ mutex_lock(&sfp->sm_mutex);
|
||||
+
|
||||
+ dev_dbg(sfp->dev, "SM: enter %s:%s:%s event %s\n",
|
||||
+ mod_state_to_str(sfp->sm_mod_state),
|
||||
+ dev_state_to_str(sfp->sm_dev_state),
|
||||
+ sm_state_to_str(sfp->sm_state),
|
||||
+ event_to_str(event));
|
||||
+
|
||||
+ sfp_sm_module(sfp, event);
|
||||
+ sfp_sm_device(sfp, event);
|
||||
+ sfp_sm_main(sfp, event);
|
||||
|
||||
dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
|
||||
mod_state_to_str(sfp->sm_mod_state),
|
||||
@ -0,0 +1,41 @@
|
||||
From 7e89b737c97a9e7a81dd1584000bc136b92f12fd Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 11 Oct 2019 22:14:47 +0100
|
||||
Subject: [PATCH 619/660] net: sfp: move tx disable on device down to main
|
||||
state machine
|
||||
|
||||
Move the tx disable assertion on device down to the main state
|
||||
machine.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 10 ++--------
|
||||
1 file changed, 2 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1554,15 +1554,8 @@ static void sfp_sm_device(struct sfp *sf
|
||||
break;
|
||||
|
||||
case SFP_DEV_UP:
|
||||
- if (event == SFP_E_DEV_DOWN) {
|
||||
- /* If the module has a PHY, avoid raising TX disable
|
||||
- * as this resets the PHY. Otherwise, raise it to
|
||||
- * turn the laser off.
|
||||
- */
|
||||
- if (!sfp->mod_phy)
|
||||
- sfp_module_tx_disable(sfp);
|
||||
+ if (event == SFP_E_DEV_DOWN)
|
||||
sfp->sm_dev_state = SFP_DEV_DOWN;
|
||||
- }
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1624,6 +1617,7 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
sfp_sm_link_down(sfp);
|
||||
if (sfp->mod_phy)
|
||||
sfp_sm_phy_detach(sfp);
|
||||
+ sfp_module_tx_disable(sfp);
|
||||
sfp_sm_next(sfp, SFP_S_DOWN, 0);
|
||||
return;
|
||||
}
|
||||
@ -0,0 +1,71 @@
|
||||
From f2a1ccfc4ad4f97c98c3cc18eb32992151ce089a Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 11 Oct 2019 22:27:21 +0100
|
||||
Subject: [PATCH 620/660] net: sfp: rename sfp_sm_ins_next() as
|
||||
sfp_sm_mod_next()
|
||||
|
||||
sfp_sm_ins_next() modifies the module state machine. Change it's name
|
||||
to reflect this.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 16 ++++++++--------
|
||||
1 file changed, 8 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1245,7 +1245,7 @@ static void sfp_sm_next(struct sfp *sfp,
|
||||
sfp_sm_set_timer(sfp, timeout);
|
||||
}
|
||||
|
||||
-static void sfp_sm_ins_next(struct sfp *sfp, unsigned int state,
|
||||
+static void sfp_sm_mod_next(struct sfp *sfp, unsigned int state,
|
||||
unsigned int timeout)
|
||||
{
|
||||
sfp->sm_mod_state = state;
|
||||
@@ -1569,22 +1569,22 @@ static void sfp_sm_module(struct sfp *sf
|
||||
default:
|
||||
if (event == SFP_E_INSERT && sfp->attached) {
|
||||
sfp_module_tx_disable(sfp);
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
|
||||
}
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
if (event == SFP_E_REMOVE) {
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
} else if (event == SFP_E_TIMEOUT) {
|
||||
int val = sfp_sm_mod_probe(sfp);
|
||||
|
||||
if (val == 0)
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
else if (val > 0)
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_HPOWER, val);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
|
||||
else if (val != -EAGAIN)
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_ERROR, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
else
|
||||
sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
}
|
||||
@@ -1592,7 +1592,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
|
||||
case SFP_MOD_HPOWER:
|
||||
if (event == SFP_E_TIMEOUT) {
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
@@ -1600,7 +1600,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
case SFP_MOD_ERROR:
|
||||
if (event == SFP_E_REMOVE) {
|
||||
sfp_sm_mod_remove(sfp);
|
||||
- sfp_sm_ins_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
From d2591ea5520e2ee8fa557f96bb64c23cafac4b20 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 15 Oct 2019 10:33:13 +0100
|
||||
Subject: [PATCH 621/660] net: sfp: handle module remove outside state machine
|
||||
|
||||
Removing a module resets the module state machine back to its initial
|
||||
state. Rather than explicitly handling this in every state, handle it
|
||||
early on outside of the state machine.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 16 +++++++++-------
|
||||
1 file changed, 9 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1565,6 +1565,14 @@ static void sfp_sm_device(struct sfp *sf
|
||||
*/
|
||||
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
+ /* Handle remove event globally, it resets this state machine */
|
||||
+ if (event == SFP_E_REMOVE) {
|
||||
+ if (sfp->sm_mod_state > SFP_MOD_PROBE)
|
||||
+ sfp_sm_mod_remove(sfp);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
switch (sfp->sm_mod_state) {
|
||||
default:
|
||||
if (event == SFP_E_INSERT && sfp->attached) {
|
||||
@@ -1574,9 +1582,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
- if (event == SFP_E_REMOVE) {
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
- } else if (event == SFP_E_TIMEOUT) {
|
||||
+ if (event == SFP_E_TIMEOUT) {
|
||||
int val = sfp_sm_mod_probe(sfp);
|
||||
|
||||
if (val == 0)
|
||||
@@ -1598,10 +1604,6 @@ static void sfp_sm_module(struct sfp *sf
|
||||
/* fallthrough */
|
||||
case SFP_MOD_PRESENT:
|
||||
case SFP_MOD_ERROR:
|
||||
- if (event == SFP_E_REMOVE) {
|
||||
- sfp_sm_mod_remove(sfp);
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
- }
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,51 @@
|
||||
From 615090acb3c0b41691f3a03522ea38350387c0e4 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 15 Oct 2019 10:54:15 +0100
|
||||
Subject: [PATCH 622/660] net: sfp: rename T_PROBE_WAIT to T_SERIAL
|
||||
|
||||
SFF-8472 rev 12.2 defines the time for the serial bus to become ready
|
||||
using t_serial. Use this as our identifier for this timeout to make
|
||||
it clear what we are referring to.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 13 ++++++-------
|
||||
1 file changed, 6 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -149,11 +149,10 @@ static const enum gpiod_flags gpio_flags
|
||||
* the same length on the PCB, which means it's possible for MOD DEF 0 to
|
||||
* connect before the I2C bus on MOD DEF 1/2.
|
||||
*
|
||||
- * The SFP MSA specifies 300ms as t_init (the time taken for TX_FAULT to
|
||||
- * be deasserted) but makes no mention of the earliest time before we can
|
||||
- * access the I2C EEPROM. However, Avago modules require 300ms.
|
||||
+ * The SFF-8472 specifies t_serial ("Time from power on until module is
|
||||
+ * ready for data transmission over the two wire serial bus.") as 300ms.
|
||||
*/
|
||||
-#define T_PROBE_INIT msecs_to_jiffies(300)
|
||||
+#define T_SERIAL msecs_to_jiffies(300)
|
||||
#define T_HPOWER_LEVEL msecs_to_jiffies(300)
|
||||
#define T_PROBE_RETRY msecs_to_jiffies(100)
|
||||
|
||||
@@ -1560,8 +1559,8 @@ static void sfp_sm_device(struct sfp *sf
|
||||
}
|
||||
}
|
||||
|
||||
-/* This state machine tracks the insert/remove state of
|
||||
- * the module, and handles probing the on-board EEPROM.
|
||||
+/* This state machine tracks the insert/remove state of the module, probes
|
||||
+ * the on-board EEPROM, and sets up the power level.
|
||||
*/
|
||||
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
@@ -1577,7 +1576,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
default:
|
||||
if (event == SFP_E_INSERT && sfp->attached) {
|
||||
sfp_module_tx_disable(sfp);
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_PROBE_INIT);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -0,0 +1,115 @@
|
||||
From d4b8746219e8c0361e5ed6e440ab3a8a600d1f76 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 11 Oct 2019 17:24:40 +0100
|
||||
Subject: [PATCH 623/660] net: sfp: parse SFP power requirement earlier
|
||||
|
||||
Parse the SFP power requirement earlier, in preparation for moving the
|
||||
power level setup code.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
|
||||
1 file changed, 29 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -198,6 +198,8 @@ struct sfp {
|
||||
unsigned int sm_retries;
|
||||
|
||||
struct sfp_eeprom_id id;
|
||||
+ unsigned int module_power_mW;
|
||||
+
|
||||
#if IS_ENABLED(CONFIG_HWMON)
|
||||
struct sfp_diag diag;
|
||||
struct device *hwmon_dev;
|
||||
@@ -1374,17 +1376,14 @@ static void sfp_sm_mod_init(struct sfp *
|
||||
sfp_sm_probe_phy(sfp);
|
||||
}
|
||||
|
||||
-static int sfp_sm_mod_hpower(struct sfp *sfp)
|
||||
+static int sfp_module_parse_power(struct sfp *sfp)
|
||||
{
|
||||
- u32 power;
|
||||
- u8 val;
|
||||
- int err;
|
||||
+ u32 power_mW = 1000;
|
||||
|
||||
- power = 1000;
|
||||
if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_POWER_DECL))
|
||||
- power = 1500;
|
||||
+ power_mW = 1500;
|
||||
if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
|
||||
- power = 2000;
|
||||
+ power_mW = 2000;
|
||||
|
||||
if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
|
||||
(sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
|
||||
@@ -1393,23 +1392,33 @@ static int sfp_sm_mod_hpower(struct sfp
|
||||
* or requires an address change sequence, so assume that
|
||||
* the module powers up in the indicated power mode.
|
||||
*/
|
||||
- if (power > sfp->max_power_mW) {
|
||||
+ if (power_mW > sfp->max_power_mW) {
|
||||
dev_err(sfp->dev,
|
||||
"Host does not support %u.%uW modules\n",
|
||||
- power / 1000, (power / 100) % 10);
|
||||
+ power_mW / 1000, (power_mW / 100) % 10);
|
||||
return -EINVAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (power > sfp->max_power_mW) {
|
||||
+ if (power_mW > sfp->max_power_mW) {
|
||||
dev_warn(sfp->dev,
|
||||
"Host does not support %u.%uW modules, module left in power mode 1\n",
|
||||
- power / 1000, (power / 100) % 10);
|
||||
+ power_mW / 1000, (power_mW / 100) % 10);
|
||||
return 0;
|
||||
}
|
||||
|
||||
- if (power <= 1000)
|
||||
+ sfp->module_power_mW = power_mW;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int sfp_sm_mod_hpower(struct sfp *sfp)
|
||||
+{
|
||||
+ u8 val;
|
||||
+ int err;
|
||||
+
|
||||
+ if (sfp->module_power_mW <= 1000)
|
||||
return 0;
|
||||
|
||||
err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
|
||||
@@ -1429,7 +1438,8 @@ static int sfp_sm_mod_hpower(struct sfp
|
||||
}
|
||||
|
||||
dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
|
||||
- power / 1000, (power / 100) % 10);
|
||||
+ sfp->module_power_mW / 1000,
|
||||
+ (sfp->module_power_mW / 100) % 10);
|
||||
return T_HPOWER_LEVEL;
|
||||
|
||||
err:
|
||||
@@ -1516,6 +1526,11 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
dev_warn(sfp->dev,
|
||||
"module address swap to access page 0xA2 is not supported.\n");
|
||||
|
||||
+ /* Parse the module power requirement */
|
||||
+ ret = sfp_module_parse_power(sfp);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
ret = sfp_hwmon_insert(sfp);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
@@ -1539,6 +1554,7 @@ static void sfp_sm_mod_remove(struct sfp
|
||||
sfp_module_tx_disable(sfp);
|
||||
|
||||
memset(&sfp->id, 0, sizeof(sfp->id));
|
||||
+ sfp->module_power_mW = 0;
|
||||
|
||||
dev_info(sfp->dev, "module removed\n");
|
||||
}
|
||||
@ -0,0 +1,65 @@
|
||||
From dca678b8838945572cf50584cb33a7199c1fd397 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 17 Oct 2019 00:24:18 +0100
|
||||
Subject: [PATCH 624/660] net: sfp: avoid power switch on address-change
|
||||
modules
|
||||
|
||||
If the module indicates that it requires an address change sequence to
|
||||
switch between address 0x50 and 0x51, which we don't support, we can't
|
||||
write to the register that controls the power mode to switch to high
|
||||
power mode. Warn the user that the module may not be functional in
|
||||
this case, and don't try to change the power mode.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 31 ++++++++++++++++++++-----------
|
||||
1 file changed, 20 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1385,25 +1385,34 @@ static int sfp_module_parse_power(struct
|
||||
if (sfp->id.ext.options & cpu_to_be16(SFP_OPTIONS_HIGH_POWER_LEVEL))
|
||||
power_mW = 2000;
|
||||
|
||||
- if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE &&
|
||||
- (sfp->id.ext.diagmon & (SFP_DIAGMON_DDM | SFP_DIAGMON_ADDRMODE)) !=
|
||||
- SFP_DIAGMON_DDM) {
|
||||
- /* The module appears not to implement bus address 0xa2,
|
||||
- * or requires an address change sequence, so assume that
|
||||
- * the module powers up in the indicated power mode.
|
||||
- */
|
||||
- if (power_mW > sfp->max_power_mW) {
|
||||
+ if (power_mW > sfp->max_power_mW) {
|
||||
+ /* Module power specification exceeds the allowed maximum. */
|
||||
+ if (sfp->id.ext.sff8472_compliance ==
|
||||
+ SFP_SFF8472_COMPLIANCE_NONE &&
|
||||
+ !(sfp->id.ext.diagmon & SFP_DIAGMON_DDM)) {
|
||||
+ /* The module appears not to implement bus address
|
||||
+ * 0xa2, so assume that the module powers up in the
|
||||
+ * indicated mode.
|
||||
+ */
|
||||
dev_err(sfp->dev,
|
||||
"Host does not support %u.%uW modules\n",
|
||||
power_mW / 1000, (power_mW / 100) % 10);
|
||||
return -EINVAL;
|
||||
+ } else {
|
||||
+ dev_warn(sfp->dev,
|
||||
+ "Host does not support %u.%uW modules, module left in power mode 1\n",
|
||||
+ power_mW / 1000, (power_mW / 100) % 10);
|
||||
+ return 0;
|
||||
}
|
||||
- return 0;
|
||||
}
|
||||
|
||||
- if (power_mW > sfp->max_power_mW) {
|
||||
+ /* If the module requires a higher power mode, but also requires
|
||||
+ * an address change sequence, warn the user that the module may
|
||||
+ * not be functional.
|
||||
+ */
|
||||
+ if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE && power_mW > 1000) {
|
||||
dev_warn(sfp->dev,
|
||||
- "Host does not support %u.%uW modules, module left in power mode 1\n",
|
||||
+ "Address Change Sequence not supported but module requies %u.%uW, module may not be functional\n",
|
||||
power_mW / 1000, (power_mW / 100) % 10);
|
||||
return 0;
|
||||
}
|
||||
@ -0,0 +1,52 @@
|
||||
From df5c4d93c5a59cba0f7479a4cd4e22b50726ce88 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 17 Oct 2019 11:12:42 +0100
|
||||
Subject: [PATCH 625/660] net: sfp: control TX_DISABLE and phy only from main
|
||||
state machine
|
||||
|
||||
We initialise TX_DISABLE when the sfp cage is probed, and then
|
||||
maintain its state in the main state machine. However, the module
|
||||
state machine:
|
||||
- negates it when detecting a newly inserted module when it's already
|
||||
guaranteed to be negated.
|
||||
- negates it when the module is removed, but the main state machine
|
||||
will do this anyway.
|
||||
|
||||
Make TX_DISABLE entirely controlled by the main state machine.
|
||||
|
||||
The main state machine also probes the module for a PHY, and removes
|
||||
the PHY when the the module is removed. Hence, removing the PHY in
|
||||
sfp_sm_module_remove() is also redundant, and is a left-over from
|
||||
when we tried to probe for the PHY from the module state machine.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 9 +--------
|
||||
1 file changed, 1 insertion(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1557,11 +1557,6 @@ static void sfp_sm_mod_remove(struct sfp
|
||||
|
||||
sfp_hwmon_remove(sfp);
|
||||
|
||||
- if (sfp->mod_phy)
|
||||
- sfp_sm_phy_detach(sfp);
|
||||
-
|
||||
- sfp_module_tx_disable(sfp);
|
||||
-
|
||||
memset(&sfp->id, 0, sizeof(sfp->id));
|
||||
sfp->module_power_mW = 0;
|
||||
|
||||
@@ -1599,10 +1594,8 @@ static void sfp_sm_module(struct sfp *sf
|
||||
|
||||
switch (sfp->sm_mod_state) {
|
||||
default:
|
||||
- if (event == SFP_E_INSERT && sfp->attached) {
|
||||
- sfp_module_tx_disable(sfp);
|
||||
+ if (event == SFP_E_INSERT && sfp->attached)
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
|
||||
- }
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
@ -0,0 +1,53 @@
|
||||
From 5ed0bd49b2d3ac4439c2d7f44e5a82b7cf6f409a Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 18 Oct 2019 10:09:02 +0100
|
||||
Subject: [PATCH 626/660] net: sfp: split the PHY probe from sfp_sm_mod_init()
|
||||
|
||||
Move the PHY probe into a separate function, splitting it from
|
||||
sfp_sm_mod_init(). This will allow us to eliminate the 50ms mdelay()
|
||||
inside the state machine.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 21 +++++++++++++--------
|
||||
1 file changed, 13 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1353,14 +1353,10 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
static void sfp_sm_mod_init(struct sfp *sfp)
|
||||
{
|
||||
sfp_module_tx_enable(sfp);
|
||||
+}
|
||||
|
||||
- /* Wait t_init before indicating that the link is up, provided the
|
||||
- * current state indicates no TX_FAULT. If TX_FAULT clears before
|
||||
- * this time, that's fine too.
|
||||
- */
|
||||
- sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
|
||||
- sfp->sm_retries = 5;
|
||||
-
|
||||
+static void sfp_sm_probe_for_phy(struct sfp *sfp)
|
||||
+{
|
||||
/* Setting the serdes link mode is guesswork: there's no
|
||||
* field in the EEPROM which indicates what mode should
|
||||
* be used.
|
||||
@@ -1645,8 +1641,17 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
switch (sfp->sm_state) {
|
||||
case SFP_S_DOWN:
|
||||
if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
|
||||
- sfp->sm_dev_state == SFP_DEV_UP)
|
||||
+ sfp->sm_dev_state == SFP_DEV_UP) {
|
||||
sfp_sm_mod_init(sfp);
|
||||
+ sfp_sm_probe_for_phy(sfp);
|
||||
+
|
||||
+ /* Wait t_init before indicating that the link is up,
|
||||
+ * provided the current state indicates no TX_FAULT. If
|
||||
+ * TX_FAULT clears before this time, that's fine too.
|
||||
+ */
|
||||
+ sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
|
||||
+ sfp->sm_retries = 5;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case SFP_S_INIT:
|
||||
@ -0,0 +1,130 @@
|
||||
From 0fe72afaa31f98ebd71bd6683fc47021105d0157 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 18 Oct 2019 10:21:46 +0100
|
||||
Subject: [PATCH 627/660] net: sfp: eliminate mdelay() from PHY probe
|
||||
|
||||
Rather than using mdelay() to wait before probing the PHY (which holds
|
||||
several locks, including the rtnl lock), add an extra wait state to
|
||||
the state machine to introduce the 50ms delay without holding any
|
||||
locks.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 52 +++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 40 insertions(+), 12 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -54,6 +54,7 @@ enum {
|
||||
SFP_DEV_UP,
|
||||
|
||||
SFP_S_DOWN = 0,
|
||||
+ SFP_S_WAIT,
|
||||
SFP_S_INIT,
|
||||
SFP_S_WAIT_LOS,
|
||||
SFP_S_LINK_UP,
|
||||
@@ -110,6 +111,7 @@ static const char *event_to_str(unsigned
|
||||
|
||||
static const char * const sm_state_strings[] = {
|
||||
[SFP_S_DOWN] = "down",
|
||||
+ [SFP_S_WAIT] = "wait",
|
||||
[SFP_S_INIT] = "init",
|
||||
[SFP_S_WAIT_LOS] = "wait_los",
|
||||
[SFP_S_LINK_UP] = "link_up",
|
||||
@@ -141,6 +143,7 @@ static const enum gpiod_flags gpio_flags
|
||||
GPIOD_ASIS,
|
||||
};
|
||||
|
||||
+#define T_WAIT msecs_to_jiffies(50)
|
||||
#define T_INIT_JIFFIES msecs_to_jiffies(300)
|
||||
#define T_RESET_US 10
|
||||
#define T_FAULT_RECOVER msecs_to_jiffies(1000)
|
||||
@@ -161,9 +164,6 @@ static const enum gpiod_flags gpio_flags
|
||||
*/
|
||||
#define SFP_PHY_ADDR 22
|
||||
|
||||
-/* Give this long for the PHY to reset. */
|
||||
-#define T_PHY_RESET_MS 50
|
||||
-
|
||||
struct sff_data {
|
||||
unsigned int gpios;
|
||||
bool (*module_supported)(const struct sfp_eeprom_id *id);
|
||||
@@ -1267,8 +1267,6 @@ static void sfp_sm_probe_phy(struct sfp
|
||||
struct phy_device *phy;
|
||||
int err;
|
||||
|
||||
- msleep(T_PHY_RESET_MS);
|
||||
-
|
||||
phy = mdiobus_scan(sfp->i2c_mii, SFP_PHY_ADDR);
|
||||
if (phy == ERR_PTR(-ENODEV)) {
|
||||
dev_info(sfp->dev, "no PHY detected\n");
|
||||
@@ -1623,6 +1621,8 @@ static void sfp_sm_module(struct sfp *sf
|
||||
|
||||
static void sfp_sm_main(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
+ unsigned long timeout;
|
||||
+
|
||||
/* Some events are global */
|
||||
if (sfp->sm_state != SFP_S_DOWN &&
|
||||
(sfp->sm_mod_state != SFP_MOD_PRESENT ||
|
||||
@@ -1640,17 +1640,45 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
/* The main state machine */
|
||||
switch (sfp->sm_state) {
|
||||
case SFP_S_DOWN:
|
||||
- if (sfp->sm_mod_state == SFP_MOD_PRESENT &&
|
||||
- sfp->sm_dev_state == SFP_DEV_UP) {
|
||||
- sfp_sm_mod_init(sfp);
|
||||
- sfp_sm_probe_for_phy(sfp);
|
||||
+ if (sfp->sm_mod_state != SFP_MOD_PRESENT ||
|
||||
+ sfp->sm_dev_state != SFP_DEV_UP)
|
||||
+ break;
|
||||
+
|
||||
+ sfp_sm_mod_init(sfp);
|
||||
+
|
||||
+ /* Initialise the fault clearance retries */
|
||||
+ sfp->sm_retries = 5;
|
||||
+
|
||||
+ /* We need to check the TX_FAULT state, which is not defined
|
||||
+ * while TX_DISABLE is asserted. The earliest we want to do
|
||||
+ * anything (such as probe for a PHY) is 50ms.
|
||||
+ */
|
||||
+ sfp_sm_next(sfp, SFP_S_WAIT, T_WAIT);
|
||||
+ break;
|
||||
+
|
||||
+ case SFP_S_WAIT:
|
||||
+ if (event != SFP_E_TIMEOUT)
|
||||
+ break;
|
||||
+
|
||||
+ sfp_sm_probe_for_phy(sfp);
|
||||
|
||||
+ if (sfp->state & SFP_F_TX_FAULT) {
|
||||
/* Wait t_init before indicating that the link is up,
|
||||
* provided the current state indicates no TX_FAULT. If
|
||||
* TX_FAULT clears before this time, that's fine too.
|
||||
*/
|
||||
- sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
|
||||
- sfp->sm_retries = 5;
|
||||
+ timeout = T_INIT_JIFFIES;
|
||||
+ if (timeout > T_WAIT)
|
||||
+ timeout -= T_WAIT;
|
||||
+ else
|
||||
+ timeout = 1;
|
||||
+
|
||||
+ sfp_sm_next(sfp, SFP_S_INIT, timeout);
|
||||
+ } else {
|
||||
+ /* TX_FAULT is not asserted, assume the module has
|
||||
+ * finished initialising.
|
||||
+ */
|
||||
+ goto init_done;
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1658,7 +1686,7 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
|
||||
sfp_sm_fault(sfp, true);
|
||||
else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
|
||||
- sfp_sm_link_check_los(sfp);
|
||||
+ init_done: sfp_sm_link_check_los(sfp);
|
||||
break;
|
||||
|
||||
case SFP_S_WAIT_LOS:
|
||||
@ -0,0 +1,69 @@
|
||||
From 2aa424ee7fbe43e2cd24e28c2f6388c4e1796bd2 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 18 Oct 2019 09:58:33 +0100
|
||||
Subject: [PATCH 628/660] net: sfp: allow fault processing to transition to
|
||||
other states
|
||||
|
||||
Add the next state to sfp_sm_fault() so that it can branch to other
|
||||
states. This will be necessary to improve the initialisation path.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 12 ++++++------
|
||||
1 file changed, 6 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -1334,7 +1334,7 @@ static bool sfp_los_event_inactive(struc
|
||||
event == SFP_E_LOS_LOW);
|
||||
}
|
||||
|
||||
-static void sfp_sm_fault(struct sfp *sfp, bool warn)
|
||||
+static void sfp_sm_fault(struct sfp *sfp, unsigned int next_state, bool warn)
|
||||
{
|
||||
if (sfp->sm_retries && !--sfp->sm_retries) {
|
||||
dev_err(sfp->dev,
|
||||
@@ -1344,7 +1344,7 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
if (warn)
|
||||
dev_err(sfp->dev, "module transmit fault indicated\n");
|
||||
|
||||
- sfp_sm_next(sfp, SFP_S_TX_FAULT, T_FAULT_RECOVER);
|
||||
+ sfp_sm_next(sfp, next_state, T_FAULT_RECOVER);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1684,14 +1684,14 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
|
||||
case SFP_S_INIT:
|
||||
if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
|
||||
- sfp_sm_fault(sfp, true);
|
||||
+ sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
|
||||
else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
|
||||
init_done: sfp_sm_link_check_los(sfp);
|
||||
break;
|
||||
|
||||
case SFP_S_WAIT_LOS:
|
||||
if (event == SFP_E_TX_FAULT)
|
||||
- sfp_sm_fault(sfp, true);
|
||||
+ sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
|
||||
else if (sfp_los_event_inactive(sfp, event))
|
||||
sfp_sm_link_up(sfp);
|
||||
break;
|
||||
@@ -1699,7 +1699,7 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
case SFP_S_LINK_UP:
|
||||
if (event == SFP_E_TX_FAULT) {
|
||||
sfp_sm_link_down(sfp);
|
||||
- sfp_sm_fault(sfp, true);
|
||||
+ sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
|
||||
} else if (sfp_los_event_active(sfp, event)) {
|
||||
sfp_sm_link_down(sfp);
|
||||
sfp_sm_next(sfp, SFP_S_WAIT_LOS, 0);
|
||||
@@ -1715,7 +1715,7 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
|
||||
case SFP_S_REINIT:
|
||||
if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
|
||||
- sfp_sm_fault(sfp, false);
|
||||
+ sfp_sm_fault(sfp, SFP_S_TX_FAULT, false);
|
||||
} else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
|
||||
dev_info(sfp->dev, "module transmit fault recovered\n");
|
||||
sfp_sm_link_check_los(sfp);
|
||||
@ -0,0 +1,80 @@
|
||||
From 38b62a12231be4b86fc5ca5477579d29831c02a5 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 18 Oct 2019 10:31:07 +0100
|
||||
Subject: [PATCH 629/660] net: sfp: ensure TX_FAULT has deasserted before
|
||||
probing the PHY
|
||||
|
||||
TX_FAULT should be deasserted to indicate that the module has completed
|
||||
its initialisation. This may include the on-board PHY, so wait until
|
||||
the module has deasserted TX_FAULT before probing the PHY.
|
||||
|
||||
This means that we need an extra state to handle a TX_FAULT that
|
||||
remains set for longer than t_init, since using the existing handling
|
||||
state would bypass the PHY probe.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 31 +++++++++++++++++++++++++------
|
||||
1 file changed, 25 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -56,6 +56,7 @@ enum {
|
||||
SFP_S_DOWN = 0,
|
||||
SFP_S_WAIT,
|
||||
SFP_S_INIT,
|
||||
+ SFP_S_INIT_TX_FAULT,
|
||||
SFP_S_WAIT_LOS,
|
||||
SFP_S_LINK_UP,
|
||||
SFP_S_TX_FAULT,
|
||||
@@ -113,6 +114,7 @@ static const char * const sm_state_strin
|
||||
[SFP_S_DOWN] = "down",
|
||||
[SFP_S_WAIT] = "wait",
|
||||
[SFP_S_INIT] = "init",
|
||||
+ [SFP_S_INIT_TX_FAULT] = "init_tx_fault",
|
||||
[SFP_S_WAIT_LOS] = "wait_los",
|
||||
[SFP_S_LINK_UP] = "link_up",
|
||||
[SFP_S_TX_FAULT] = "tx_fault",
|
||||
@@ -1660,8 +1662,6 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
if (event != SFP_E_TIMEOUT)
|
||||
break;
|
||||
|
||||
- sfp_sm_probe_for_phy(sfp);
|
||||
-
|
||||
if (sfp->state & SFP_F_TX_FAULT) {
|
||||
/* Wait t_init before indicating that the link is up,
|
||||
* provided the current state indicates no TX_FAULT. If
|
||||
@@ -1683,10 +1683,29 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
break;
|
||||
|
||||
case SFP_S_INIT:
|
||||
- if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT)
|
||||
- sfp_sm_fault(sfp, SFP_S_TX_FAULT, true);
|
||||
- else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR)
|
||||
- init_done: sfp_sm_link_check_los(sfp);
|
||||
+ if (event == SFP_E_TIMEOUT && sfp->state & SFP_F_TX_FAULT) {
|
||||
+ /* TX_FAULT is still asserted after t_init, so assume
|
||||
+ * there is a fault.
|
||||
+ */
|
||||
+ sfp_sm_fault(sfp, SFP_S_INIT_TX_FAULT,
|
||||
+ sfp->sm_retries == 5);
|
||||
+ } else if (event == SFP_E_TIMEOUT || event == SFP_E_TX_CLEAR) {
|
||||
+ init_done: /* TX_FAULT deasserted or we timed out with TX_FAULT
|
||||
+ * clear. Probe for the PHY and check the LOS state.
|
||||
+ */
|
||||
+ sfp_sm_probe_for_phy(sfp);
|
||||
+ sfp_sm_link_check_los(sfp);
|
||||
+
|
||||
+ /* Reset the fault retry count */
|
||||
+ sfp->sm_retries = 5;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case SFP_S_INIT_TX_FAULT:
|
||||
+ if (event == SFP_E_TIMEOUT) {
|
||||
+ sfp_module_tx_fault_reset(sfp);
|
||||
+ sfp_sm_next(sfp, SFP_S_INIT, T_INIT_JIFFIES);
|
||||
+ }
|
||||
break;
|
||||
|
||||
case SFP_S_WAIT_LOS:
|
||||
@ -0,0 +1,153 @@
|
||||
From ec6036a58f979c66bbd5cd9d0d1c783a98c2c644 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 12:57:40 +0000
|
||||
Subject: [PATCH 630/660] net: sfp: track upstream's attachment state in state
|
||||
machine
|
||||
|
||||
Track the upstream's attachment state in the state machine rather than
|
||||
maintaining a boolean, which ensures that we have a strict order of
|
||||
ATTACH followed by an UP event - we can never believe that a newly
|
||||
attached upstream will be anything but down.
|
||||
|
||||
Rearrange the order of state machines so we run the module state
|
||||
machine after the upstream device's state machine, so the module state
|
||||
machine can check the current state of the device and take action to
|
||||
e.g. reset back to empty state when the upstream is detached.
|
||||
|
||||
This is to allow the module detection to run independently of the
|
||||
network device becoming available.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 42 +++++++++++++++++++++++++++++-------------
|
||||
1 file changed, 29 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -36,6 +36,8 @@ enum {
|
||||
|
||||
SFP_E_INSERT = 0,
|
||||
SFP_E_REMOVE,
|
||||
+ SFP_E_DEV_ATTACH,
|
||||
+ SFP_E_DEV_DETACH,
|
||||
SFP_E_DEV_DOWN,
|
||||
SFP_E_DEV_UP,
|
||||
SFP_E_TX_FAULT,
|
||||
@@ -50,7 +52,8 @@ enum {
|
||||
SFP_MOD_PRESENT,
|
||||
SFP_MOD_ERROR,
|
||||
|
||||
- SFP_DEV_DOWN = 0,
|
||||
+ SFP_DEV_DETACHED = 0,
|
||||
+ SFP_DEV_DOWN,
|
||||
SFP_DEV_UP,
|
||||
|
||||
SFP_S_DOWN = 0,
|
||||
@@ -80,6 +83,7 @@ static const char *mod_state_to_str(unsi
|
||||
}
|
||||
|
||||
static const char * const dev_state_strings[] = {
|
||||
+ [SFP_DEV_DETACHED] = "detached",
|
||||
[SFP_DEV_DOWN] = "down",
|
||||
[SFP_DEV_UP] = "up",
|
||||
};
|
||||
@@ -94,6 +98,8 @@ static const char *dev_state_to_str(unsi
|
||||
static const char * const event_strings[] = {
|
||||
[SFP_E_INSERT] = "insert",
|
||||
[SFP_E_REMOVE] = "remove",
|
||||
+ [SFP_E_DEV_ATTACH] = "dev_attach",
|
||||
+ [SFP_E_DEV_DETACH] = "dev_detach",
|
||||
[SFP_E_DEV_DOWN] = "dev_down",
|
||||
[SFP_E_DEV_UP] = "dev_up",
|
||||
[SFP_E_TX_FAULT] = "tx_fault",
|
||||
@@ -188,7 +194,6 @@ struct sfp {
|
||||
struct gpio_desc *gpio[GPIO_MAX];
|
||||
int gpio_irq[GPIO_MAX];
|
||||
|
||||
- bool attached;
|
||||
struct mutex st_mutex; /* Protects state */
|
||||
unsigned int state;
|
||||
struct delayed_work poll;
|
||||
@@ -1559,17 +1564,26 @@ static void sfp_sm_mod_remove(struct sfp
|
||||
dev_info(sfp->dev, "module removed\n");
|
||||
}
|
||||
|
||||
-/* This state machine tracks the netdev up/down state */
|
||||
+/* This state machine tracks the upstream's state */
|
||||
static void sfp_sm_device(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
switch (sfp->sm_dev_state) {
|
||||
default:
|
||||
- if (event == SFP_E_DEV_UP)
|
||||
+ if (event == SFP_E_DEV_ATTACH)
|
||||
+ sfp->sm_dev_state = SFP_DEV_DOWN;
|
||||
+ break;
|
||||
+
|
||||
+ case SFP_DEV_DOWN:
|
||||
+ if (event == SFP_E_DEV_DETACH)
|
||||
+ sfp->sm_dev_state = SFP_DEV_DETACHED;
|
||||
+ else if (event == SFP_E_DEV_UP)
|
||||
sfp->sm_dev_state = SFP_DEV_UP;
|
||||
break;
|
||||
|
||||
case SFP_DEV_UP:
|
||||
- if (event == SFP_E_DEV_DOWN)
|
||||
+ if (event == SFP_E_DEV_DETACH)
|
||||
+ sfp->sm_dev_state = SFP_DEV_DETACHED;
|
||||
+ else if (event == SFP_E_DEV_DOWN)
|
||||
sfp->sm_dev_state = SFP_DEV_DOWN;
|
||||
break;
|
||||
}
|
||||
@@ -1580,17 +1594,20 @@ static void sfp_sm_device(struct sfp *sf
|
||||
*/
|
||||
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
- /* Handle remove event globally, it resets this state machine */
|
||||
- if (event == SFP_E_REMOVE) {
|
||||
+ /* Handle remove event globally, it resets this state machine.
|
||||
+ * Also deal with upstream detachment.
|
||||
+ */
|
||||
+ if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
|
||||
if (sfp->sm_mod_state > SFP_MOD_PROBE)
|
||||
sfp_sm_mod_remove(sfp);
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ if (sfp->sm_mod_state != SFP_MOD_EMPTY)
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sfp->sm_mod_state) {
|
||||
default:
|
||||
- if (event == SFP_E_INSERT && sfp->attached)
|
||||
+ if (event == SFP_E_INSERT)
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
|
||||
break;
|
||||
|
||||
@@ -1756,8 +1773,8 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
sm_state_to_str(sfp->sm_state),
|
||||
event_to_str(event));
|
||||
|
||||
- sfp_sm_module(sfp, event);
|
||||
sfp_sm_device(sfp, event);
|
||||
+ sfp_sm_module(sfp, event);
|
||||
sfp_sm_main(sfp, event);
|
||||
|
||||
dev_dbg(sfp->dev, "SM: exit %s:%s:%s\n",
|
||||
@@ -1770,15 +1787,14 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
|
||||
static void sfp_attach(struct sfp *sfp)
|
||||
{
|
||||
- sfp->attached = true;
|
||||
+ sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
|
||||
if (sfp->state & SFP_F_PRESENT)
|
||||
sfp_sm_event(sfp, SFP_E_INSERT);
|
||||
}
|
||||
|
||||
static void sfp_detach(struct sfp *sfp)
|
||||
{
|
||||
- sfp->attached = false;
|
||||
- sfp_sm_event(sfp, SFP_E_REMOVE);
|
||||
+ sfp_sm_event(sfp, SFP_E_DEV_DETACH);
|
||||
}
|
||||
|
||||
static void sfp_start(struct sfp *sfp)
|
||||
@ -0,0 +1,184 @@
|
||||
From fdff863a4ce3677907f64396e34c45025abb6600 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 12:59:36 +0000
|
||||
Subject: [PATCH 631/660] net: sfp: split power mode switching from probe
|
||||
|
||||
Switch the power mode switching from the probe, so that we don't
|
||||
repeatedly re-probe the SFP device if there is a problem accessing
|
||||
the registers at I2C address 0x51.
|
||||
|
||||
In splitting this out, we can also fix a bug where we leave the module
|
||||
in high-power mode when the upstream device is detached but the module
|
||||
is still inserted.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 101 ++++++++++++++++++++++++++----------------
|
||||
1 file changed, 64 insertions(+), 37 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -49,6 +49,7 @@ enum {
|
||||
SFP_MOD_EMPTY = 0,
|
||||
SFP_MOD_PROBE,
|
||||
SFP_MOD_HPOWER,
|
||||
+ SFP_MOD_WAITPWR,
|
||||
SFP_MOD_PRESENT,
|
||||
SFP_MOD_ERROR,
|
||||
|
||||
@@ -71,6 +72,7 @@ static const char * const mod_state_str
|
||||
[SFP_MOD_EMPTY] = "empty",
|
||||
[SFP_MOD_PROBE] = "probe",
|
||||
[SFP_MOD_HPOWER] = "hpower",
|
||||
+ [SFP_MOD_WAITPWR] = "waitpwr",
|
||||
[SFP_MOD_PRESENT] = "present",
|
||||
[SFP_MOD_ERROR] = "error",
|
||||
};
|
||||
@@ -1423,37 +1425,34 @@ static int sfp_module_parse_power(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int sfp_sm_mod_hpower(struct sfp *sfp)
|
||||
+static int sfp_sm_mod_hpower(struct sfp *sfp, bool enable)
|
||||
{
|
||||
u8 val;
|
||||
int err;
|
||||
|
||||
- if (sfp->module_power_mW <= 1000)
|
||||
- return 0;
|
||||
-
|
||||
err = sfp_read(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
|
||||
if (err != sizeof(val)) {
|
||||
dev_err(sfp->dev, "Failed to read EEPROM: %d\n", err);
|
||||
- err = -EAGAIN;
|
||||
- goto err;
|
||||
+ return -EAGAIN;
|
||||
}
|
||||
|
||||
- val |= BIT(0);
|
||||
+ if (enable)
|
||||
+ val |= BIT(0);
|
||||
+ else
|
||||
+ val &= ~BIT(0);
|
||||
|
||||
err = sfp_write(sfp, true, SFP_EXT_STATUS, &val, sizeof(val));
|
||||
if (err != sizeof(val)) {
|
||||
dev_err(sfp->dev, "Failed to write EEPROM: %d\n", err);
|
||||
- err = -EAGAIN;
|
||||
- goto err;
|
||||
+ return -EAGAIN;
|
||||
}
|
||||
|
||||
- dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
|
||||
- sfp->module_power_mW / 1000,
|
||||
- (sfp->module_power_mW / 100) % 10);
|
||||
- return T_HPOWER_LEVEL;
|
||||
+ if (enable)
|
||||
+ dev_info(sfp->dev, "Module switched to %u.%uW power level\n",
|
||||
+ sfp->module_power_mW / 1000,
|
||||
+ (sfp->module_power_mW / 100) % 10);
|
||||
|
||||
-err:
|
||||
- return err;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static int sfp_sm_mod_probe(struct sfp *sfp)
|
||||
@@ -1549,7 +1548,7 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- return sfp_sm_mod_hpower(sfp);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void sfp_sm_mod_remove(struct sfp *sfp)
|
||||
@@ -1594,13 +1593,22 @@ static void sfp_sm_device(struct sfp *sf
|
||||
*/
|
||||
static void sfp_sm_module(struct sfp *sfp, unsigned int event)
|
||||
{
|
||||
- /* Handle remove event globally, it resets this state machine.
|
||||
- * Also deal with upstream detachment.
|
||||
- */
|
||||
- if (event == SFP_E_REMOVE || sfp->sm_dev_state < SFP_DEV_DOWN) {
|
||||
+ int err;
|
||||
+
|
||||
+ /* Handle remove event globally, it resets this state machine */
|
||||
+ if (event == SFP_E_REMOVE) {
|
||||
if (sfp->sm_mod_state > SFP_MOD_PROBE)
|
||||
sfp_sm_mod_remove(sfp);
|
||||
- if (sfp->sm_mod_state != SFP_MOD_EMPTY)
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Handle device detach globally */
|
||||
+ if (sfp->sm_dev_state < SFP_DEV_DOWN) {
|
||||
+ if (sfp->module_power_mW > 1000 &&
|
||||
+ sfp->sm_mod_state > SFP_MOD_HPOWER)
|
||||
+ sfp_sm_mod_hpower(sfp, false);
|
||||
+ if (sfp->sm_mod_state > SFP_MOD_EMPTY)
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
return;
|
||||
}
|
||||
@@ -1612,26 +1620,45 @@ static void sfp_sm_module(struct sfp *sf
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
- if (event == SFP_E_TIMEOUT) {
|
||||
- int val = sfp_sm_mod_probe(sfp);
|
||||
+ if (event != SFP_E_TIMEOUT)
|
||||
+ break;
|
||||
|
||||
- if (val == 0)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
- else if (val > 0)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, val);
|
||||
- else if (val != -EAGAIN)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
- else
|
||||
- sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ err = sfp_sm_mod_probe(sfp);
|
||||
+ if (err == -EAGAIN) {
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ break;
|
||||
}
|
||||
- break;
|
||||
+ if (err < 0) {
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ /* If this is a power level 1 module, we are done */
|
||||
+ if (sfp->module_power_mW <= 1000)
|
||||
+ goto insert;
|
||||
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_HPOWER, 0);
|
||||
+ /* fall through */
|
||||
case SFP_MOD_HPOWER:
|
||||
- if (event == SFP_E_TIMEOUT) {
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
+ /* Enable high power mode */
|
||||
+ err = sfp_sm_mod_hpower(sfp, true);
|
||||
+ if (err == 0)
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
|
||||
+ else if (err != -EAGAIN)
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
+ else
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ break;
|
||||
+
|
||||
+ case SFP_MOD_WAITPWR:
|
||||
+ /* Wait for T_HPOWER_LEVEL to time out */
|
||||
+ if (event != SFP_E_TIMEOUT)
|
||||
break;
|
||||
- }
|
||||
- /* fallthrough */
|
||||
+
|
||||
+ insert:
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_PRESENT, 0);
|
||||
+ break;
|
||||
+
|
||||
case SFP_MOD_PRESENT:
|
||||
case SFP_MOD_ERROR:
|
||||
break;
|
||||
@ -0,0 +1,159 @@
|
||||
From 57cbf7453551db1df619b79410d79fc418d862d5 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 13:00:45 +0000
|
||||
Subject: [PATCH 632/660] net: sfp: move module insert reporting out of probe
|
||||
|
||||
Move the module insertion reporting out of the probe handling, but
|
||||
after we have detected that the upstream has attached (since that is
|
||||
whom we are reporting insertion to.)
|
||||
|
||||
Only report module removal if we had previously reported a module
|
||||
insertion.
|
||||
|
||||
This gives cleaner semantics, and means we can probe the module before
|
||||
we have an upstream attached.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 58 +++++++++++++++++++++++++++++--------------
|
||||
1 file changed, 40 insertions(+), 18 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -47,11 +47,12 @@ enum {
|
||||
SFP_E_TIMEOUT,
|
||||
|
||||
SFP_MOD_EMPTY = 0,
|
||||
+ SFP_MOD_ERROR,
|
||||
SFP_MOD_PROBE,
|
||||
+ SFP_MOD_WAITDEV,
|
||||
SFP_MOD_HPOWER,
|
||||
SFP_MOD_WAITPWR,
|
||||
SFP_MOD_PRESENT,
|
||||
- SFP_MOD_ERROR,
|
||||
|
||||
SFP_DEV_DETACHED = 0,
|
||||
SFP_DEV_DOWN,
|
||||
@@ -70,11 +71,12 @@ enum {
|
||||
|
||||
static const char * const mod_state_strings[] = {
|
||||
[SFP_MOD_EMPTY] = "empty",
|
||||
+ [SFP_MOD_ERROR] = "error",
|
||||
[SFP_MOD_PROBE] = "probe",
|
||||
+ [SFP_MOD_WAITDEV] = "waitdev",
|
||||
[SFP_MOD_HPOWER] = "hpower",
|
||||
[SFP_MOD_WAITPWR] = "waitpwr",
|
||||
[SFP_MOD_PRESENT] = "present",
|
||||
- [SFP_MOD_ERROR] = "error",
|
||||
};
|
||||
|
||||
static const char *mod_state_to_str(unsigned short mod_state)
|
||||
@@ -1544,16 +1546,13 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = sfp_module_insert(sfp->sfp_bus, &sfp->id);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sfp_sm_mod_remove(struct sfp *sfp)
|
||||
{
|
||||
- sfp_module_remove(sfp->sfp_bus);
|
||||
+ if (sfp->sm_mod_state > SFP_MOD_WAITDEV)
|
||||
+ sfp_module_remove(sfp->sfp_bus);
|
||||
|
||||
sfp_hwmon_remove(sfp);
|
||||
|
||||
@@ -1604,12 +1603,12 @@ static void sfp_sm_module(struct sfp *sf
|
||||
}
|
||||
|
||||
/* Handle device detach globally */
|
||||
- if (sfp->sm_dev_state < SFP_DEV_DOWN) {
|
||||
+ if (sfp->sm_dev_state < SFP_DEV_DOWN &&
|
||||
+ sfp->sm_mod_state > SFP_MOD_WAITDEV) {
|
||||
if (sfp->module_power_mW > 1000 &&
|
||||
sfp->sm_mod_state > SFP_MOD_HPOWER)
|
||||
sfp_sm_mod_hpower(sfp, false);
|
||||
- if (sfp->sm_mod_state > SFP_MOD_EMPTY)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_EMPTY, 0);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1620,6 +1619,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
+ /* Wait for T_PROBE_INIT to time out */
|
||||
if (event != SFP_E_TIMEOUT)
|
||||
break;
|
||||
|
||||
@@ -1633,6 +1633,20 @@ static void sfp_sm_module(struct sfp *sf
|
||||
break;
|
||||
}
|
||||
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_WAITDEV, 0);
|
||||
+ /* fall through */
|
||||
+ case SFP_MOD_WAITDEV:
|
||||
+ /* Ensure that the device is attached before proceeding */
|
||||
+ if (sfp->sm_dev_state < SFP_DEV_DOWN)
|
||||
+ break;
|
||||
+
|
||||
+ /* Report the module insertion to the upstream device */
|
||||
+ err = sfp_module_insert(sfp->sfp_bus, &sfp->id);
|
||||
+ if (err < 0) {
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
/* If this is a power level 1 module, we are done */
|
||||
if (sfp->module_power_mW <= 1000)
|
||||
goto insert;
|
||||
@@ -1642,12 +1656,17 @@ static void sfp_sm_module(struct sfp *sf
|
||||
case SFP_MOD_HPOWER:
|
||||
/* Enable high power mode */
|
||||
err = sfp_sm_mod_hpower(sfp, true);
|
||||
- if (err == 0)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
|
||||
- else if (err != -EAGAIN)
|
||||
- sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
- else
|
||||
- sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ if (err < 0) {
|
||||
+ if (err != -EAGAIN) {
|
||||
+ sfp_module_remove(sfp->sfp_bus);
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
+ } else {
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ sfp_sm_mod_next(sfp, SFP_MOD_WAITPWR, T_HPOWER_LEVEL);
|
||||
break;
|
||||
|
||||
case SFP_MOD_WAITPWR:
|
||||
@@ -1815,8 +1834,6 @@ static void sfp_sm_event(struct sfp *sfp
|
||||
static void sfp_attach(struct sfp *sfp)
|
||||
{
|
||||
sfp_sm_event(sfp, SFP_E_DEV_ATTACH);
|
||||
- if (sfp->state & SFP_F_PRESENT)
|
||||
- sfp_sm_event(sfp, SFP_E_INSERT);
|
||||
}
|
||||
|
||||
static void sfp_detach(struct sfp *sfp)
|
||||
@@ -2084,6 +2101,11 @@ static int sfp_probe(struct platform_dev
|
||||
sfp->state |= SFP_F_RATE_SELECT;
|
||||
sfp_set_state(sfp, sfp->state);
|
||||
sfp_module_tx_disable(sfp);
|
||||
+ if (sfp->state & SFP_F_PRESENT) {
|
||||
+ rtnl_lock();
|
||||
+ sfp_sm_event(sfp, SFP_E_INSERT);
|
||||
+ rtnl_unlock();
|
||||
+ }
|
||||
|
||||
for (i = 0; i < GPIO_MAX; i++) {
|
||||
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
|
||||
@ -0,0 +1,110 @@
|
||||
From fb56cd08880aff8fb030e684fa4311bef712a499 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 13:02:30 +0000
|
||||
Subject: [PATCH 633/660] net: sfp: allow sfp to probe slow to initialise GPON
|
||||
modules
|
||||
|
||||
Some GPON modules (e.g. Huawei MA5671A) take a significant amount of
|
||||
time to start responding on the I2C bus, contary to the SFF
|
||||
specifications.
|
||||
|
||||
Work around this by implementing a two-level timeout strategy, where
|
||||
we initially quickly retry for the module, and then use a slower retry
|
||||
after we exceed a maximum number of quick attempts.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 38 ++++++++++++++++++++++++++++----------
|
||||
1 file changed, 28 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -167,9 +167,12 @@ static const enum gpiod_flags gpio_flags
|
||||
* The SFF-8472 specifies t_serial ("Time from power on until module is
|
||||
* ready for data transmission over the two wire serial bus.") as 300ms.
|
||||
*/
|
||||
-#define T_SERIAL msecs_to_jiffies(300)
|
||||
-#define T_HPOWER_LEVEL msecs_to_jiffies(300)
|
||||
-#define T_PROBE_RETRY msecs_to_jiffies(100)
|
||||
+#define T_SERIAL msecs_to_jiffies(300)
|
||||
+#define T_HPOWER_LEVEL msecs_to_jiffies(300)
|
||||
+#define T_PROBE_RETRY_INIT msecs_to_jiffies(100)
|
||||
+#define R_PROBE_RETRY_INIT 10
|
||||
+#define T_PROBE_RETRY_SLOW msecs_to_jiffies(5000)
|
||||
+#define R_PROBE_RETRY_SLOW 12
|
||||
|
||||
/* SFP modules appear to always have their PHY configured for bus address
|
||||
* 0x56 (which with mdio-i2c, translates to a PHY address of 22).
|
||||
@@ -204,6 +207,8 @@ struct sfp {
|
||||
struct delayed_work timeout;
|
||||
struct mutex sm_mutex; /* Protects state machine */
|
||||
unsigned char sm_mod_state;
|
||||
+ unsigned char sm_mod_tries_init;
|
||||
+ unsigned char sm_mod_tries;
|
||||
unsigned char sm_dev_state;
|
||||
unsigned short sm_state;
|
||||
unsigned int sm_retries;
|
||||
@@ -1457,7 +1462,7 @@ static int sfp_sm_mod_hpower(struct sfp
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int sfp_sm_mod_probe(struct sfp *sfp)
|
||||
+static int sfp_sm_mod_probe(struct sfp *sfp, bool report)
|
||||
{
|
||||
/* SFP module inserted - read I2C data */
|
||||
struct sfp_eeprom_id id;
|
||||
@@ -1467,7 +1472,8 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
|
||||
ret = sfp_read(sfp, false, 0, &id, sizeof(id));
|
||||
if (ret < 0) {
|
||||
- dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
|
||||
+ if (report)
|
||||
+ dev_err(sfp->dev, "failed to read EEPROM: %d\n", ret);
|
||||
return -EAGAIN;
|
||||
}
|
||||
|
||||
@@ -1614,8 +1620,11 @@ static void sfp_sm_module(struct sfp *sf
|
||||
|
||||
switch (sfp->sm_mod_state) {
|
||||
default:
|
||||
- if (event == SFP_E_INSERT)
|
||||
+ if (event == SFP_E_INSERT) {
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_PROBE, T_SERIAL);
|
||||
+ sfp->sm_mod_tries_init = R_PROBE_RETRY_INIT;
|
||||
+ sfp->sm_mod_tries = R_PROBE_RETRY_SLOW;
|
||||
+ }
|
||||
break;
|
||||
|
||||
case SFP_MOD_PROBE:
|
||||
@@ -1623,10 +1632,19 @@ static void sfp_sm_module(struct sfp *sf
|
||||
if (event != SFP_E_TIMEOUT)
|
||||
break;
|
||||
|
||||
- err = sfp_sm_mod_probe(sfp);
|
||||
+ err = sfp_sm_mod_probe(sfp, sfp->sm_mod_tries == 1);
|
||||
if (err == -EAGAIN) {
|
||||
- sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
- break;
|
||||
+ if (sfp->sm_mod_tries_init &&
|
||||
+ --sfp->sm_mod_tries_init) {
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
|
||||
+ break;
|
||||
+ } else if (sfp->sm_mod_tries && --sfp->sm_mod_tries) {
|
||||
+ if (sfp->sm_mod_tries == R_PROBE_RETRY_SLOW - 1)
|
||||
+ dev_warn(sfp->dev,
|
||||
+ "please wait, module slow to respond\n");
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY_SLOW);
|
||||
+ break;
|
||||
+ }
|
||||
}
|
||||
if (err < 0) {
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
@@ -1661,7 +1679,7 @@ static void sfp_sm_module(struct sfp *sf
|
||||
sfp_module_remove(sfp->sfp_bus);
|
||||
sfp_sm_mod_next(sfp, SFP_MOD_ERROR, 0);
|
||||
} else {
|
||||
- sfp_sm_set_timer(sfp, T_PROBE_RETRY);
|
||||
+ sfp_sm_set_timer(sfp, T_PROBE_RETRY_INIT);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -0,0 +1,198 @@
|
||||
From 559391fc20fae506adcb311b904cc544c76436c0 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Thu, 7 Nov 2019 18:52:07 +0000
|
||||
Subject: [PATCH 634/660] net: sfp: allow modules with slow diagnostics to
|
||||
probe
|
||||
|
||||
When a module is inserted, we attempt to read read the ID from address
|
||||
0x50. Once we are able to read the ID, we immediately attempt to
|
||||
initialise the hwmon support by reading from address 0x51. If this
|
||||
fails, then we fall into error state, and assume that the module is
|
||||
not usable.
|
||||
|
||||
Modules such as the ALCATELLUCENT 3FE46541AA use a real EEPROM for
|
||||
I2C address 0x50, which responds immediately. However, address 0x51
|
||||
is an emulated, which only becomes available once the on-board firmware
|
||||
has booted. This prompts us to fall into the error state.
|
||||
|
||||
Since the module may be usable without diagnostics, arrange for the
|
||||
hwmon probe independent of the rest of the SFP itself, retrying every
|
||||
5s for up to about 60s for the monitoring to become available, and
|
||||
print an error message if it doesn't become available.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 96 +++++++++++++++++++++++++++++++++----------
|
||||
1 file changed, 74 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -218,6 +218,8 @@ struct sfp {
|
||||
|
||||
#if IS_ENABLED(CONFIG_HWMON)
|
||||
struct sfp_diag diag;
|
||||
+ struct delayed_work hwmon_probe;
|
||||
+ unsigned int hwmon_tries;
|
||||
struct device *hwmon_dev;
|
||||
char *hwmon_name;
|
||||
#endif
|
||||
@@ -1159,29 +1161,27 @@ static const struct hwmon_chip_info sfp_
|
||||
.info = sfp_hwmon_info,
|
||||
};
|
||||
|
||||
-static int sfp_hwmon_insert(struct sfp *sfp)
|
||||
+static void sfp_hwmon_probe(struct work_struct *work)
|
||||
{
|
||||
+ struct sfp *sfp = container_of(work, struct sfp, hwmon_probe.work);
|
||||
int err, i;
|
||||
|
||||
- if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE)
|
||||
- return 0;
|
||||
-
|
||||
- if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM))
|
||||
- return 0;
|
||||
-
|
||||
- if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
|
||||
- /* This driver in general does not support address
|
||||
- * change.
|
||||
- */
|
||||
- return 0;
|
||||
-
|
||||
err = sfp_read(sfp, true, 0, &sfp->diag, sizeof(sfp->diag));
|
||||
- if (err < 0)
|
||||
- return err;
|
||||
+ if (err < 0) {
|
||||
+ if (sfp->hwmon_tries--) {
|
||||
+ mod_delayed_work(system_wq, &sfp->hwmon_probe,
|
||||
+ T_PROBE_RETRY_SLOW);
|
||||
+ } else {
|
||||
+ dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
|
||||
+ }
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
sfp->hwmon_name = kstrdup(dev_name(sfp->dev), GFP_KERNEL);
|
||||
- if (!sfp->hwmon_name)
|
||||
- return -ENODEV;
|
||||
+ if (!sfp->hwmon_name) {
|
||||
+ dev_err(sfp->dev, "out of memory for hwmon name\n");
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
for (i = 0; sfp->hwmon_name[i]; i++)
|
||||
if (hwmon_is_bad_char(sfp->hwmon_name[i]))
|
||||
@@ -1191,18 +1191,52 @@ static int sfp_hwmon_insert(struct sfp *
|
||||
sfp->hwmon_name, sfp,
|
||||
&sfp_hwmon_chip_info,
|
||||
NULL);
|
||||
+ if (IS_ERR(sfp->hwmon_dev))
|
||||
+ dev_err(sfp->dev, "failed to register hwmon device: %ld\n",
|
||||
+ PTR_ERR(sfp->hwmon_dev));
|
||||
+}
|
||||
+
|
||||
+static int sfp_hwmon_insert(struct sfp *sfp)
|
||||
+{
|
||||
+ if (sfp->id.ext.sff8472_compliance == SFP_SFF8472_COMPLIANCE_NONE)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (!(sfp->id.ext.diagmon & SFP_DIAGMON_DDM))
|
||||
+ return 0;
|
||||
+
|
||||
+ if (sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE)
|
||||
+ /* This driver in general does not support address
|
||||
+ * change.
|
||||
+ */
|
||||
+ return 0;
|
||||
+
|
||||
+ mod_delayed_work(system_wq, &sfp->hwmon_probe, 1);
|
||||
+ sfp->hwmon_tries = R_PROBE_RETRY_SLOW;
|
||||
|
||||
- return PTR_ERR_OR_ZERO(sfp->hwmon_dev);
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
static void sfp_hwmon_remove(struct sfp *sfp)
|
||||
{
|
||||
+ cancel_delayed_work_sync(&sfp->hwmon_probe);
|
||||
if (!IS_ERR_OR_NULL(sfp->hwmon_dev)) {
|
||||
hwmon_device_unregister(sfp->hwmon_dev);
|
||||
sfp->hwmon_dev = NULL;
|
||||
kfree(sfp->hwmon_name);
|
||||
}
|
||||
}
|
||||
+
|
||||
+static int sfp_hwmon_init(struct sfp *sfp)
|
||||
+{
|
||||
+ INIT_DELAYED_WORK(&sfp->hwmon_probe, sfp_hwmon_probe);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void sfp_hwmon_exit(struct sfp *sfp)
|
||||
+{
|
||||
+ cancel_delayed_work_sync(&sfp->hwmon_probe);
|
||||
+}
|
||||
#else
|
||||
static int sfp_hwmon_insert(struct sfp *sfp)
|
||||
{
|
||||
@@ -1212,6 +1246,15 @@ static int sfp_hwmon_insert(struct sfp *
|
||||
static void sfp_hwmon_remove(struct sfp *sfp)
|
||||
{
|
||||
}
|
||||
+
|
||||
+static int sfp_hwmon_init(struct sfp *sfp)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void sfp_hwmon_exit(struct sfp *sfp)
|
||||
+{
|
||||
+}
|
||||
#endif
|
||||
|
||||
/* Helpers */
|
||||
@@ -1548,10 +1591,6 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = sfp_hwmon_insert(sfp);
|
||||
- if (ret < 0)
|
||||
- return ret;
|
||||
-
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1700,6 +1739,15 @@ static void sfp_sm_module(struct sfp *sf
|
||||
case SFP_MOD_ERROR:
|
||||
break;
|
||||
}
|
||||
+
|
||||
+#if IS_ENABLED(CONFIG_HWMON)
|
||||
+ if (sfp->sm_mod_state >= SFP_MOD_WAITDEV &&
|
||||
+ IS_ERR_OR_NULL(sfp->hwmon_dev)) {
|
||||
+ err = sfp_hwmon_insert(sfp);
|
||||
+ if (err)
|
||||
+ dev_warn(sfp->dev, "hwmon probe failed: %d\n", err);
|
||||
+ }
|
||||
+#endif
|
||||
}
|
||||
|
||||
static void sfp_sm_main(struct sfp *sfp, unsigned int event)
|
||||
@@ -2001,6 +2049,8 @@ static struct sfp *sfp_alloc(struct devi
|
||||
INIT_DELAYED_WORK(&sfp->poll, sfp_poll);
|
||||
INIT_DELAYED_WORK(&sfp->timeout, sfp_timeout);
|
||||
|
||||
+ sfp_hwmon_init(sfp);
|
||||
+
|
||||
return sfp;
|
||||
}
|
||||
|
||||
@@ -2008,6 +2058,8 @@ static void sfp_cleanup(void *data)
|
||||
{
|
||||
struct sfp *sfp = data;
|
||||
|
||||
+ sfp_hwmon_exit(sfp);
|
||||
+
|
||||
cancel_delayed_work_sync(&sfp->poll);
|
||||
cancel_delayed_work_sync(&sfp->timeout);
|
||||
if (sfp->i2c_mii) {
|
||||
@ -0,0 +1,183 @@
|
||||
From eb156db588ac583cdae7b91eaac9c0ad3a358e63 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sun, 15 Sep 2019 20:05:34 +0100
|
||||
Subject: [PATCH 635/660] net: phy: add core phylib sfp support
|
||||
|
||||
Add core phylib help for supporting SFP sockets on PHYs. This provides
|
||||
a mechanism to inform the SFP layer about PHY up/down events, and also
|
||||
unregister the SFP bus when the PHY is going away.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy.c | 7 ++++
|
||||
drivers/net/phy/phy_device.c | 66 ++++++++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 11 ++++++
|
||||
3 files changed, 84 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy.c
|
||||
+++ b/drivers/net/phy/phy.c
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <linux/ethtool.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_led_triggers.h>
|
||||
+#include <linux/sfp.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/io.h>
|
||||
@@ -842,6 +843,9 @@ void phy_stop(struct phy_device *phydev)
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
|
||||
+ if (phydev->sfp_bus)
|
||||
+ sfp_upstream_stop(phydev->sfp_bus);
|
||||
+
|
||||
phydev->state = PHY_HALTED;
|
||||
|
||||
mutex_unlock(&phydev->lock);
|
||||
@@ -904,6 +908,9 @@ void phy_state_machine(struct work_struc
|
||||
|
||||
old_state = phydev->state;
|
||||
|
||||
+ if (phydev->sfp_bus)
|
||||
+ sfp_upstream_start(phydev->sfp_bus);
|
||||
+
|
||||
switch (phydev->state) {
|
||||
case PHY_DOWN:
|
||||
case PHY_READY:
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <linux/bitmap.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_led_triggers.h>
|
||||
+#include <linux/sfp.h>
|
||||
#include <linux/mdio.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
@@ -1183,6 +1184,65 @@ phy_standalone_show(struct device *dev,
|
||||
static DEVICE_ATTR_RO(phy_standalone);
|
||||
|
||||
/**
|
||||
+ * phy_sfp_attach - attach the SFP bus to the PHY upstream network device
|
||||
+ * @upstream: pointer to the phy device
|
||||
+ * @bus: sfp bus representing cage being attached
|
||||
+ *
|
||||
+ * This is used to fill in the sfp_upstream_ops .attach member.
|
||||
+ */
|
||||
+void phy_sfp_attach(void *upstream, struct sfp_bus *bus)
|
||||
+{
|
||||
+ struct phy_device *phydev = upstream;
|
||||
+
|
||||
+ if (phydev->attached_dev)
|
||||
+ phydev->attached_dev->sfp_bus = bus;
|
||||
+ phydev->sfp_bus_attached = true;
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_sfp_attach);
|
||||
+
|
||||
+/**
|
||||
+ * phy_sfp_detach - detach the SFP bus from the PHY upstream network device
|
||||
+ * @upstream: pointer to the phy device
|
||||
+ * @bus: sfp bus representing cage being attached
|
||||
+ *
|
||||
+ * This is used to fill in the sfp_upstream_ops .detach member.
|
||||
+ */
|
||||
+void phy_sfp_detach(void *upstream, struct sfp_bus *bus)
|
||||
+{
|
||||
+ struct phy_device *phydev = upstream;
|
||||
+
|
||||
+ if (phydev->attached_dev)
|
||||
+ phydev->attached_dev->sfp_bus = NULL;
|
||||
+ phydev->sfp_bus_attached = false;
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_sfp_detach);
|
||||
+
|
||||
+/**
|
||||
+ * phy_sfp_probe - probe for a SFP cage attached to this PHY device
|
||||
+ * @phydev: Pointer to phy_device
|
||||
+ * @ops: SFP's upstream operations
|
||||
+ */
|
||||
+int phy_sfp_probe(struct phy_device *phydev,
|
||||
+ const struct sfp_upstream_ops *ops)
|
||||
+{
|
||||
+ struct sfp_bus *bus;
|
||||
+ int ret;
|
||||
+
|
||||
+ if (phydev->mdio.dev.fwnode) {
|
||||
+ bus = sfp_bus_find_fwnode(phydev->mdio.dev.fwnode);
|
||||
+ if (IS_ERR(bus))
|
||||
+ return PTR_ERR(bus);
|
||||
+
|
||||
+ phydev->sfp_bus = bus;
|
||||
+
|
||||
+ ret = sfp_bus_add_upstream(bus, phydev, ops);
|
||||
+ sfp_bus_put(bus);
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_sfp_probe);
|
||||
+
|
||||
+/**
|
||||
* phy_attach_direct - attach a network device to a given PHY device pointer
|
||||
* @dev: network device to attach
|
||||
* @phydev: Pointer to phy_device to attach
|
||||
@@ -1259,6 +1319,9 @@ int phy_attach_direct(struct net_device
|
||||
dev->phydev = phydev;
|
||||
}
|
||||
|
||||
+ if (phydev->sfp_bus_attached)
|
||||
+ dev->sfp_bus = phydev->sfp_bus;
|
||||
+
|
||||
/* Some Ethernet drivers try to connect to a PHY device before
|
||||
* calling register_netdevice() -> netdev_register_kobject() and
|
||||
* does the dev->dev.kobj initialization. Here we only check for
|
||||
@@ -2287,6 +2350,9 @@ static int phy_remove(struct device *dev
|
||||
phydev->state = PHY_DOWN;
|
||||
mutex_unlock(&phydev->lock);
|
||||
|
||||
+ sfp_bus_del_upstream(phydev->sfp_bus);
|
||||
+ phydev->sfp_bus = NULL;
|
||||
+
|
||||
if (phydev->drv && phydev->drv->remove) {
|
||||
phydev->drv->remove(phydev);
|
||||
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -203,6 +203,8 @@ static inline const char *phy_modes(phy_
|
||||
|
||||
struct device;
|
||||
struct phylink;
|
||||
+struct sfp_bus;
|
||||
+struct sfp_upstream_ops;
|
||||
struct sk_buff;
|
||||
|
||||
/*
|
||||
@@ -343,6 +345,8 @@ struct phy_c45_device_ids {
|
||||
* dev_flags: Device-specific flags used by the PHY driver.
|
||||
* irq: IRQ number of the PHY's interrupt (-1 if none)
|
||||
* phy_timer: The timer for handling the state machine
|
||||
+ * sfp_bus_attached: flag indicating whether the SFP bus has been attached
|
||||
+ * sfp_bus: SFP bus attached to this PHY's fiber port
|
||||
* attached_dev: The attached enet driver's device instance ptr
|
||||
* adjust_link: Callback for the enet controller to respond to
|
||||
* changes in the link state.
|
||||
@@ -434,6 +438,9 @@ struct phy_device {
|
||||
|
||||
struct mutex lock;
|
||||
|
||||
+ /* This may be modified under the rtnl lock */
|
||||
+ bool sfp_bus_attached;
|
||||
+ struct sfp_bus *sfp_bus;
|
||||
struct phylink *phylink;
|
||||
struct net_device *attached_dev;
|
||||
|
||||
@@ -1023,6 +1030,10 @@ int phy_suspend(struct phy_device *phyde
|
||||
int phy_resume(struct phy_device *phydev);
|
||||
int __phy_resume(struct phy_device *phydev);
|
||||
int phy_loopback(struct phy_device *phydev, bool enable);
|
||||
+void phy_sfp_attach(void *upstream, struct sfp_bus *bus);
|
||||
+void phy_sfp_detach(void *upstream, struct sfp_bus *bus);
|
||||
+int phy_sfp_probe(struct phy_device *phydev,
|
||||
+ const struct sfp_upstream_ops *ops);
|
||||
struct phy_device *phy_attach(struct net_device *dev, const char *bus_id,
|
||||
phy_interface_t interface);
|
||||
struct phy_device *phy_find_first(struct mii_bus *bus);
|
||||
@ -0,0 +1,67 @@
|
||||
From 0836d9fb41ed90090ef4af0d7abe784ee7706f80 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 14 Apr 2017 14:21:25 +0100
|
||||
Subject: [PATCH 636/660] net: phy: marvell10g: add SFP+ support
|
||||
|
||||
Add support for SFP+ cages to the Marvell 10G PHY driver. This is
|
||||
slightly complicated by the way phylib works in that we need to use
|
||||
a multi-step process to attach the SFP bus, and we also need to track
|
||||
the phylink state machine to know when the module's transmit disable
|
||||
signal should change state.
|
||||
|
||||
With appropriate DT changes, this allows the SFP+ canges on the
|
||||
Macchiatobin platform to be functional.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/marvell10g.c | 25 ++++++++++++++++++++++++-
|
||||
1 file changed, 24 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/phy/marvell10g.c
|
||||
+++ b/drivers/net/phy/marvell10g.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/marvell_phy.h>
|
||||
#include <linux/phy.h>
|
||||
+#include <linux/sfp.h>
|
||||
|
||||
#define MV_PHY_ALASKA_NBT_QUIRK_MASK 0xfffffffe
|
||||
#define MV_PHY_ALASKA_NBT_QUIRK_REV (MARVELL_PHY_ID_88X3310 | 0xa)
|
||||
@@ -206,6 +207,28 @@ static int mv3310_hwmon_probe(struct phy
|
||||
}
|
||||
#endif
|
||||
|
||||
+static int mv3310_sfp_insert(void *upstream, const struct sfp_eeprom_id *id)
|
||||
+{
|
||||
+ struct phy_device *phydev = upstream;
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||
+ phy_interface_t iface;
|
||||
+
|
||||
+ sfp_parse_support(phydev->sfp_bus, id, support);
|
||||
+ iface = sfp_select_interface(phydev->sfp_bus, id, support);
|
||||
+
|
||||
+ if (iface != PHY_INTERFACE_MODE_10GKR) {
|
||||
+ dev_err(&phydev->mdio.dev, "incompatible SFP module inserted\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct sfp_upstream_ops mv3310_sfp_ops = {
|
||||
+ .attach = phy_sfp_attach,
|
||||
+ .detach = phy_sfp_detach,
|
||||
+ .module_insert = mv3310_sfp_insert,
|
||||
+};
|
||||
+
|
||||
static int mv3310_probe(struct phy_device *phydev)
|
||||
{
|
||||
struct mv3310_priv *priv;
|
||||
@@ -236,7 +259,7 @@ static int mv3310_probe(struct phy_devic
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- return 0;
|
||||
+ return phy_sfp_probe(phydev, &mv3310_sfp_ops);
|
||||
}
|
||||
|
||||
static int mv3310_suspend(struct phy_device *phydev)
|
||||
@ -0,0 +1,43 @@
|
||||
From 09d7d8395ec61fba4392b35baa6f71c4e36489df Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 8 Nov 2019 15:18:02 +0000
|
||||
Subject: [PATCH 637/660] net: phylink: update to use phy_support_asym_pause()
|
||||
|
||||
Use phy_support_asym_pause() rather than open-coding it.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 17 +++++++----------
|
||||
1 file changed, 7 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -718,11 +718,6 @@ static int phylink_bringup_phy(struct ph
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(supported);
|
||||
int ret;
|
||||
|
||||
- memset(&config, 0, sizeof(config));
|
||||
- linkmode_copy(supported, phy->supported);
|
||||
- linkmode_copy(config.advertising, phy->advertising);
|
||||
- config.interface = pl->link_config.interface;
|
||||
-
|
||||
/*
|
||||
* This is the new way of dealing with flow control for PHYs,
|
||||
* as described by Timur Tabi in commit 529ed1275263 ("net: phy:
|
||||
@@ -730,10 +725,12 @@ static int phylink_bringup_phy(struct ph
|
||||
* using our validate call to the MAC, we rely upon the MAC
|
||||
* clearing the bits from both supported and advertising fields.
|
||||
*/
|
||||
- if (phylink_test(supported, Pause))
|
||||
- phylink_set(config.advertising, Pause);
|
||||
- if (phylink_test(supported, Asym_Pause))
|
||||
- phylink_set(config.advertising, Asym_Pause);
|
||||
+ phy_support_asym_pause(phy);
|
||||
+
|
||||
+ memset(&config, 0, sizeof(config));
|
||||
+ linkmode_copy(supported, phy->supported);
|
||||
+ linkmode_copy(config.advertising, phy->advertising);
|
||||
+ config.interface = pl->link_config.interface;
|
||||
|
||||
ret = phylink_validate(pl, supported, &config);
|
||||
if (ret)
|
||||
@ -0,0 +1,111 @@
|
||||
From 8df5dd55cef48c0769379e04dbc085a899b106d4 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 8 Mar 2019 14:02:25 +0000
|
||||
Subject: [PATCH 640/660] net: sfp: add support for module quirks
|
||||
|
||||
Add support for applying module quirks to the list of supported
|
||||
ethtool link modes.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 54 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 54 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -10,6 +10,12 @@
|
||||
|
||||
#include "sfp.h"
|
||||
|
||||
+struct sfp_quirk {
|
||||
+ const char *vendor;
|
||||
+ const char *part;
|
||||
+ void (*modes)(const struct sfp_eeprom_id *id, unsigned long *modes);
|
||||
+};
|
||||
+
|
||||
/**
|
||||
* struct sfp_bus - internal representation of a sfp bus
|
||||
*/
|
||||
@@ -22,6 +28,7 @@ struct sfp_bus {
|
||||
const struct sfp_socket_ops *socket_ops;
|
||||
struct device *sfp_dev;
|
||||
struct sfp *sfp;
|
||||
+ const struct sfp_quirk *sfp_quirk;
|
||||
|
||||
const struct sfp_upstream_ops *upstream_ops;
|
||||
void *upstream;
|
||||
@@ -31,6 +38,46 @@ struct sfp_bus {
|
||||
bool started;
|
||||
};
|
||||
|
||||
+static const struct sfp_quirk sfp_quirks[] = {
|
||||
+};
|
||||
+
|
||||
+static size_t sfp_strlen(const char *str, size_t maxlen)
|
||||
+{
|
||||
+ size_t size, i;
|
||||
+
|
||||
+ /* Trailing characters should be filled with space chars */
|
||||
+ for (i = 0, size = 0; i < maxlen; i++)
|
||||
+ if (str[i] != ' ')
|
||||
+ size = i + 1;
|
||||
+
|
||||
+ return size;
|
||||
+}
|
||||
+
|
||||
+static bool sfp_match(const char *qs, const char *str, size_t len)
|
||||
+{
|
||||
+ if (!qs)
|
||||
+ return true;
|
||||
+ if (strlen(qs) != len)
|
||||
+ return false;
|
||||
+ return !strncmp(qs, str, len);
|
||||
+}
|
||||
+
|
||||
+static const struct sfp_quirk *sfp_lookup_quirk(const struct sfp_eeprom_id *id)
|
||||
+{
|
||||
+ const struct sfp_quirk *q;
|
||||
+ unsigned int i;
|
||||
+ size_t vs, ps;
|
||||
+
|
||||
+ vs = sfp_strlen(id->base.vendor_name, ARRAY_SIZE(id->base.vendor_name));
|
||||
+ ps = sfp_strlen(id->base.vendor_pn, ARRAY_SIZE(id->base.vendor_pn));
|
||||
+
|
||||
+ for (i = 0, q = sfp_quirks; i < ARRAY_SIZE(sfp_quirks); i++, q++)
|
||||
+ if (sfp_match(q->vendor, id->base.vendor_name, vs) &&
|
||||
+ sfp_match(q->part, id->base.vendor_pn, ps))
|
||||
+ return q;
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
/**
|
||||
* sfp_parse_port() - Parse the EEPROM base ID, setting the port type
|
||||
* @bus: a pointer to the &struct sfp_bus structure for the sfp module
|
||||
@@ -234,6 +281,9 @@ void sfp_parse_support(struct sfp_bus *b
|
||||
phylink_set(modes, 1000baseX_Full);
|
||||
}
|
||||
|
||||
+ if (bus->sfp_quirk)
|
||||
+ bus->sfp_quirk->modes(id, modes);
|
||||
+
|
||||
bitmap_or(support, support, modes, __ETHTOOL_LINK_MODE_MASK_NBITS);
|
||||
|
||||
phylink_set(support, Autoneg);
|
||||
@@ -610,6 +660,8 @@ int sfp_module_insert(struct sfp_bus *bu
|
||||
const struct sfp_upstream_ops *ops = sfp_get_upstream_ops(bus);
|
||||
int ret = 0;
|
||||
|
||||
+ bus->sfp_quirk = sfp_lookup_quirk(id);
|
||||
+
|
||||
if (ops && ops->module_insert)
|
||||
ret = ops->module_insert(bus->upstream, id);
|
||||
|
||||
@@ -623,6 +675,8 @@ void sfp_module_remove(struct sfp_bus *b
|
||||
|
||||
if (ops && ops->module_remove)
|
||||
ops->module_remove(bus->upstream);
|
||||
+
|
||||
+ bus->sfp_quirk = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sfp_module_remove);
|
||||
|
||||
@ -0,0 +1,52 @@
|
||||
From ecaa542cfed078dbc356dadff0bad4b6a8e704a0 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 17 May 2019 10:14:45 +0100
|
||||
Subject: [PATCH 641/660] net: sfp: add some quirks for GPON modules
|
||||
|
||||
Marc Micalizzi reports that Huawei MA5671A and Alcatel/Lucent G-010S-P
|
||||
modules are capable of 2500base-X, but incorrectly report their
|
||||
capabilities in the EEPROM. It seems rather common that GPON modules
|
||||
mis-report.
|
||||
|
||||
Let's fix these modules by adding some quirks.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp-bus.c | 25 +++++++++++++++++++++++++
|
||||
1 file changed, 25 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -38,7 +38,32 @@ struct sfp_bus {
|
||||
bool started;
|
||||
};
|
||||
|
||||
+static void sfp_quirk_2500basex(const struct sfp_eeprom_id *id,
|
||||
+ unsigned long *modes)
|
||||
+{
|
||||
+ phylink_set(modes, 2500baseX_Full);
|
||||
+}
|
||||
+
|
||||
static const struct sfp_quirk sfp_quirks[] = {
|
||||
+ {
|
||||
+ // Alcatel Lucent G-010S-P can operate at 2500base-X, but
|
||||
+ // incorrectly report 2500MBd NRZ in their EEPROM
|
||||
+ .vendor = "ALCATELLUCENT",
|
||||
+ .part = "G010SP",
|
||||
+ .modes = sfp_quirk_2500basex,
|
||||
+ }, {
|
||||
+ // Alcatel Lucent G-010S-A can operate at 2500base-X, but
|
||||
+ // report 3.2GBd NRZ in their EEPROM
|
||||
+ .vendor = "ALCATELLUCENT",
|
||||
+ .part = "3FE46541AA",
|
||||
+ .modes = sfp_quirk_2500basex,
|
||||
+ }, {
|
||||
+ // Huawei MA5671A can operate at 2500base-X, but report 1.2GBd
|
||||
+ // NRZ in their EEPROM
|
||||
+ .vendor = "HUAWEI",
|
||||
+ .part = "MA5671A",
|
||||
+ .modes = sfp_quirk_2500basex,
|
||||
+ },
|
||||
};
|
||||
|
||||
static size_t sfp_strlen(const char *str, size_t maxlen)
|
||||
@ -0,0 +1,225 @@
|
||||
From 40e0b3b15f7da92e6b065292b14af7b9bfb1c6e0 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 13 Sep 2019 23:00:35 +0100
|
||||
Subject: [PATCH 642/660] net: sfp: soft status and control support
|
||||
|
||||
Add support for the soft status and control register, which allows
|
||||
TX_FAULT and RX_LOS to be monitored and TX_DISABLE to be set. We
|
||||
make use of this when the board does not support GPIOs for these
|
||||
signals.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 110 ++++++++++++++++++++++++++++++++++--------
|
||||
include/linux/sfp.h | 4 ++
|
||||
2 files changed, 94 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -201,7 +201,10 @@ struct sfp {
|
||||
struct gpio_desc *gpio[GPIO_MAX];
|
||||
int gpio_irq[GPIO_MAX];
|
||||
|
||||
+ bool need_poll;
|
||||
+
|
||||
struct mutex st_mutex; /* Protects state */
|
||||
+ unsigned int state_soft_mask;
|
||||
unsigned int state;
|
||||
struct delayed_work poll;
|
||||
struct delayed_work timeout;
|
||||
@@ -395,24 +398,90 @@ static int sfp_i2c_configure(struct sfp
|
||||
}
|
||||
|
||||
/* Interface */
|
||||
-static unsigned int sfp_get_state(struct sfp *sfp)
|
||||
+static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
|
||||
{
|
||||
- return sfp->get_state(sfp);
|
||||
+ return sfp->read(sfp, a2, addr, buf, len);
|
||||
}
|
||||
|
||||
-static void sfp_set_state(struct sfp *sfp, unsigned int state)
|
||||
+static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
|
||||
{
|
||||
- sfp->set_state(sfp, state);
|
||||
+ return sfp->write(sfp, a2, addr, buf, len);
|
||||
}
|
||||
|
||||
-static int sfp_read(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
|
||||
+static unsigned int sfp_soft_get_state(struct sfp *sfp)
|
||||
{
|
||||
- return sfp->read(sfp, a2, addr, buf, len);
|
||||
+ unsigned int state = 0;
|
||||
+ u8 status;
|
||||
+
|
||||
+ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
|
||||
+ sizeof(status)) {
|
||||
+ if (status & SFP_STATUS_RX_LOS)
|
||||
+ state |= SFP_F_LOS;
|
||||
+ if (status & SFP_STATUS_TX_FAULT)
|
||||
+ state |= SFP_F_TX_FAULT;
|
||||
+ }
|
||||
+
|
||||
+ return state & sfp->state_soft_mask;
|
||||
}
|
||||
|
||||
-static int sfp_write(struct sfp *sfp, bool a2, u8 addr, void *buf, size_t len)
|
||||
+static void sfp_soft_set_state(struct sfp *sfp, unsigned int state)
|
||||
{
|
||||
- return sfp->write(sfp, a2, addr, buf, len);
|
||||
+ u8 status;
|
||||
+
|
||||
+ if (sfp_read(sfp, true, SFP_STATUS, &status, sizeof(status)) ==
|
||||
+ sizeof(status)) {
|
||||
+ if (state & SFP_F_TX_DISABLE)
|
||||
+ status |= SFP_STATUS_TX_DISABLE_FORCE;
|
||||
+ else
|
||||
+ status &= ~SFP_STATUS_TX_DISABLE_FORCE;
|
||||
+
|
||||
+ sfp_write(sfp, true, SFP_STATUS, &status, sizeof(status));
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void sfp_soft_start_poll(struct sfp *sfp)
|
||||
+{
|
||||
+ const struct sfp_eeprom_id *id = &sfp->id;
|
||||
+
|
||||
+ sfp->state_soft_mask = 0;
|
||||
+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_DISABLE &&
|
||||
+ !sfp->gpio[GPIO_TX_DISABLE])
|
||||
+ sfp->state_soft_mask |= SFP_F_TX_DISABLE;
|
||||
+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_TX_FAULT &&
|
||||
+ !sfp->gpio[GPIO_TX_FAULT])
|
||||
+ sfp->state_soft_mask |= SFP_F_TX_FAULT;
|
||||
+ if (id->ext.enhopts & SFP_ENHOPTS_SOFT_RX_LOS &&
|
||||
+ !sfp->gpio[GPIO_LOS])
|
||||
+ sfp->state_soft_mask |= SFP_F_LOS;
|
||||
+
|
||||
+ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) &&
|
||||
+ !sfp->need_poll)
|
||||
+ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
||||
+}
|
||||
+
|
||||
+static void sfp_soft_stop_poll(struct sfp *sfp)
|
||||
+{
|
||||
+ sfp->state_soft_mask = 0;
|
||||
+}
|
||||
+
|
||||
+static unsigned int sfp_get_state(struct sfp *sfp)
|
||||
+{
|
||||
+ unsigned int state = sfp->get_state(sfp);
|
||||
+
|
||||
+ if (state & SFP_F_PRESENT &&
|
||||
+ sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT))
|
||||
+ state |= sfp_soft_get_state(sfp);
|
||||
+
|
||||
+ return state;
|
||||
+}
|
||||
+
|
||||
+static void sfp_set_state(struct sfp *sfp, unsigned int state)
|
||||
+{
|
||||
+ sfp->set_state(sfp, state);
|
||||
+
|
||||
+ if (state & SFP_F_PRESENT &&
|
||||
+ sfp->state_soft_mask & SFP_F_TX_DISABLE)
|
||||
+ sfp_soft_set_state(sfp, state);
|
||||
}
|
||||
|
||||
static unsigned int sfp_check(void *buf, size_t len)
|
||||
@@ -1407,11 +1476,6 @@ static void sfp_sm_fault(struct sfp *sfp
|
||||
}
|
||||
}
|
||||
|
||||
-static void sfp_sm_mod_init(struct sfp *sfp)
|
||||
-{
|
||||
- sfp_module_tx_enable(sfp);
|
||||
-}
|
||||
-
|
||||
static void sfp_sm_probe_for_phy(struct sfp *sfp)
|
||||
{
|
||||
/* Setting the serdes link mode is guesswork: there's no
|
||||
@@ -1574,7 +1638,7 @@ static int sfp_sm_mod_probe(struct sfp *
|
||||
(int)sizeof(id.ext.datecode), id.ext.datecode);
|
||||
|
||||
/* Check whether we support this module */
|
||||
- if (!sfp->type->module_supported(&sfp->id)) {
|
||||
+ if (!sfp->type->module_supported(&id)) {
|
||||
dev_err(sfp->dev,
|
||||
"module is not supported - phys id 0x%02x 0x%02x\n",
|
||||
sfp->id.base.phys_id, sfp->id.base.phys_ext_id);
|
||||
@@ -1764,6 +1828,7 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
if (sfp->mod_phy)
|
||||
sfp_sm_phy_detach(sfp);
|
||||
sfp_module_tx_disable(sfp);
|
||||
+ sfp_soft_stop_poll(sfp);
|
||||
sfp_sm_next(sfp, SFP_S_DOWN, 0);
|
||||
return;
|
||||
}
|
||||
@@ -1775,7 +1840,10 @@ static void sfp_sm_main(struct sfp *sfp,
|
||||
sfp->sm_dev_state != SFP_DEV_UP)
|
||||
break;
|
||||
|
||||
- sfp_sm_mod_init(sfp);
|
||||
+ if (!(sfp->id.ext.diagmon & SFP_DIAGMON_ADDRMODE))
|
||||
+ sfp_soft_start_poll(sfp);
|
||||
+
|
||||
+ sfp_module_tx_enable(sfp);
|
||||
|
||||
/* Initialise the fault clearance retries */
|
||||
sfp->sm_retries = 5;
|
||||
@@ -2031,7 +2099,10 @@ static void sfp_poll(struct work_struct
|
||||
struct sfp *sfp = container_of(work, struct sfp, poll.work);
|
||||
|
||||
sfp_check_state(sfp);
|
||||
- mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
||||
+
|
||||
+ if (sfp->state_soft_mask & (SFP_F_LOS | SFP_F_TX_FAULT) ||
|
||||
+ sfp->need_poll)
|
||||
+ mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
||||
}
|
||||
|
||||
static struct sfp *sfp_alloc(struct device *dev)
|
||||
@@ -2076,7 +2147,6 @@ static int sfp_probe(struct platform_dev
|
||||
const struct sff_data *sff;
|
||||
struct i2c_adapter *i2c;
|
||||
struct sfp *sfp;
|
||||
- bool poll = false;
|
||||
int err, i;
|
||||
|
||||
sfp = sfp_alloc(&pdev->dev);
|
||||
@@ -2183,7 +2253,7 @@ static int sfp_probe(struct platform_dev
|
||||
|
||||
sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
|
||||
if (!sfp->gpio_irq[i]) {
|
||||
- poll = true;
|
||||
+ sfp->need_poll = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -2195,11 +2265,11 @@ static int sfp_probe(struct platform_dev
|
||||
dev_name(sfp->dev), sfp);
|
||||
if (err) {
|
||||
sfp->gpio_irq[i] = 0;
|
||||
- poll = true;
|
||||
+ sfp->need_poll = true;
|
||||
}
|
||||
}
|
||||
|
||||
- if (poll)
|
||||
+ if (sfp->need_poll)
|
||||
mod_delayed_work(system_wq, &sfp->poll, poll_jiffies);
|
||||
|
||||
/* We could have an issue in cases no Tx disable pin is available or
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -428,6 +428,10 @@ enum {
|
||||
SFP_TEC_CUR = 0x6c,
|
||||
|
||||
SFP_STATUS = 0x6e,
|
||||
+ SFP_STATUS_TX_DISABLE = BIT(7),
|
||||
+ SFP_STATUS_TX_DISABLE_FORCE = BIT(6),
|
||||
+ SFP_STATUS_TX_FAULT = BIT(2),
|
||||
+ SFP_STATUS_RX_LOS = BIT(1),
|
||||
SFP_ALARM0 = 0x70,
|
||||
SFP_ALARM0_TEMP_HIGH = BIT(7),
|
||||
SFP_ALARM0_TEMP_LOW = BIT(6),
|
||||
@ -0,0 +1,123 @@
|
||||
From 37feab6076aa816ed72fe836759a485353241916 Mon Sep 17 00:00:00 2001
|
||||
From: DENG Qingfang <dqfext@gmail.com>
|
||||
Date: Fri, 6 Mar 2020 20:35:35 +0800
|
||||
Subject: net: dsa: mt7530: add support for port mirroring
|
||||
|
||||
Add support for configuring port mirroring through the cls_matchall
|
||||
classifier. We do a full ingress and/or egress capture towards a
|
||||
capture port.
|
||||
MT7530 supports one monitor port and multiple mirrored ports.
|
||||
|
||||
Signed-off-by: DENG Qingfang <dqfext@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/dsa/mt7530.h | 7 ++++++
|
||||
2 files changed, 67 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -1222,6 +1222,64 @@ mt7530_port_vlan_del(struct dsa_switch *
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static int mt7530_port_mirror_add(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror,
|
||||
+ bool ingress)
|
||||
+{
|
||||
+ struct mt7530_priv *priv = ds->priv;
|
||||
+ u32 val;
|
||||
+
|
||||
+ /* Check for existent entry */
|
||||
+ if ((ingress ? priv->mirror_rx : priv->mirror_tx) & BIT(port))
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ val = mt7530_read(priv, MT7530_MFC);
|
||||
+
|
||||
+ /* MT7530 only supports one monitor port */
|
||||
+ if (val & MIRROR_EN && MIRROR_PORT(val) != mirror->to_local_port)
|
||||
+ return -EEXIST;
|
||||
+
|
||||
+ val |= MIRROR_EN;
|
||||
+ val &= ~MIRROR_MASK;
|
||||
+ val |= mirror->to_local_port;
|
||||
+ mt7530_write(priv, MT7530_MFC, val);
|
||||
+
|
||||
+ val = mt7530_read(priv, MT7530_PCR_P(port));
|
||||
+ if (ingress) {
|
||||
+ val |= PORT_RX_MIR;
|
||||
+ priv->mirror_rx |= BIT(port);
|
||||
+ } else {
|
||||
+ val |= PORT_TX_MIR;
|
||||
+ priv->mirror_tx |= BIT(port);
|
||||
+ }
|
||||
+ mt7530_write(priv, MT7530_PCR_P(port), val);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void mt7530_port_mirror_del(struct dsa_switch *ds, int port,
|
||||
+ struct dsa_mall_mirror_tc_entry *mirror)
|
||||
+{
|
||||
+ struct mt7530_priv *priv = ds->priv;
|
||||
+ u32 val;
|
||||
+
|
||||
+ val = mt7530_read(priv, MT7530_PCR_P(port));
|
||||
+ if (mirror->ingress) {
|
||||
+ val &= ~PORT_RX_MIR;
|
||||
+ priv->mirror_rx &= ~BIT(port);
|
||||
+ } else {
|
||||
+ val &= ~PORT_TX_MIR;
|
||||
+ priv->mirror_tx &= ~BIT(port);
|
||||
+ }
|
||||
+ mt7530_write(priv, MT7530_PCR_P(port), val);
|
||||
+
|
||||
+ if (!priv->mirror_rx && !priv->mirror_tx) {
|
||||
+ val = mt7530_read(priv, MT7530_MFC);
|
||||
+ val &= ~MIRROR_EN;
|
||||
+ mt7530_write(priv, MT7530_MFC, val);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
static enum dsa_tag_protocol
|
||||
mtk_get_tag_protocol(struct dsa_switch *ds, int port)
|
||||
{
|
||||
@@ -1606,6 +1664,8 @@ static const struct dsa_switch_ops mt753
|
||||
.port_vlan_prepare = mt7530_port_vlan_prepare,
|
||||
.port_vlan_add = mt7530_port_vlan_add,
|
||||
.port_vlan_del = mt7530_port_vlan_del,
|
||||
+ .port_mirror_add = mt7530_port_mirror_add,
|
||||
+ .port_mirror_del = mt7530_port_mirror_del,
|
||||
.phylink_validate = mt7530_phylink_validate,
|
||||
.phylink_mac_link_state = mt7530_phylink_mac_link_state,
|
||||
.phylink_mac_config = mt7530_phylink_mac_config,
|
||||
--- a/drivers/net/dsa/mt7530.h
|
||||
+++ b/drivers/net/dsa/mt7530.h
|
||||
@@ -36,6 +36,9 @@ enum {
|
||||
#define CPU_EN BIT(7)
|
||||
#define CPU_PORT(x) ((x) << 4)
|
||||
#define CPU_MASK (0xf << 4)
|
||||
+#define MIRROR_EN BIT(3)
|
||||
+#define MIRROR_PORT(x) ((x) & 0x7)
|
||||
+#define MIRROR_MASK 0x7
|
||||
|
||||
/* Registers for address table access */
|
||||
#define MT7530_ATA1 0x74
|
||||
@@ -141,6 +144,8 @@ enum mt7530_stp_state {
|
||||
|
||||
/* Register for port control */
|
||||
#define MT7530_PCR_P(x) (0x2004 + ((x) * 0x100))
|
||||
+#define PORT_TX_MIR BIT(9)
|
||||
+#define PORT_RX_MIR BIT(8)
|
||||
#define PORT_VLAN(x) ((x) & 0x3)
|
||||
|
||||
enum mt7530_port_mode {
|
||||
@@ -460,6 +465,8 @@ struct mt7530_priv {
|
||||
phy_interface_t p6_interface;
|
||||
phy_interface_t p5_interface;
|
||||
unsigned int p5_intf_sel;
|
||||
+ u8 mirror_rx;
|
||||
+ u8 mirror_tx;
|
||||
|
||||
struct mt7530_port ports[MT7530_NUM_PORTS];
|
||||
/* protect among processes for registers access*/
|
||||
@ -0,0 +1,39 @@
|
||||
From 0452800f6db4ed0a42ffb15867c0acfd68829f6a Mon Sep 17 00:00:00 2001
|
||||
From: Chuanhong Guo <gch981213@gmail.com>
|
||||
Date: Fri, 3 Apr 2020 19:28:24 +0800
|
||||
Subject: net: dsa: mt7530: fix null pointer dereferencing in port5 setup
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
The 2nd gmac of mediatek soc ethernet may not be connected to a PHY
|
||||
and a phy-handle isn't always available.
|
||||
Unfortunately, mt7530 dsa driver assumes that the 2nd gmac is always
|
||||
connected to switch port 5 and setup mt7530 according to phy address
|
||||
of 2nd gmac node, causing null pointer dereferencing when phy-handle
|
||||
isn't defined in dts.
|
||||
This commit fix this setup code by checking return value of
|
||||
of_parse_phandle before using it.
|
||||
|
||||
Fixes: 38f790a80560 ("net: dsa: mt7530: Add support for port 5")
|
||||
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||
Reviewed-by: Vivien Didelot <vivien.didelot@gmail.com>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Tested-by: René van Dorst <opensource@vdorst.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/dsa/mt7530.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/drivers/net/dsa/mt7530.c
|
||||
+++ b/drivers/net/dsa/mt7530.c
|
||||
@@ -1411,6 +1411,9 @@ mt7530_setup(struct dsa_switch *ds)
|
||||
continue;
|
||||
|
||||
phy_node = of_parse_phandle(mac_np, "phy-handle", 0);
|
||||
+ if (!phy_node)
|
||||
+ continue;
|
||||
+
|
||||
if (phy_node->parent == priv->dev->of_node->parent) {
|
||||
interface = of_get_phy_mode(mac_np);
|
||||
id = of_mdio_parse_addr(ds->dev, phy_node);
|
||||
@ -0,0 +1,893 @@
|
||||
From 84e5ddd5c46ea3bf0cad670da32028994cad5936 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Jones <rjones@gateworks.com>
|
||||
Date: Mon, 14 Oct 2019 11:49:21 -0700
|
||||
Subject: [PATCH] iio: imu: Add support for the FXOS8700 IMU
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
FXOS8700CQ is a small, low-power, 3-axis linear accelerometer and 3-axis
|
||||
magnetometer combined into a single package. The device features a
|
||||
selectable I2C or point-to-point SPI serial interface with 14-bit
|
||||
accelerometer and 16-bit magnetometer ADC resolution along with
|
||||
smart-embedded functions.
|
||||
|
||||
FXOS8700CQ has dynamically selectable accelerationfull-scale ranges of
|
||||
±2 g/±4 g/±8 g and a fixed magnetic measurement range of ±1200 μT.
|
||||
Output data rates (ODR) from 1.563 Hz to 800 Hz are selectable by the user
|
||||
for each sensor. Interleaved magnetic and acceleration data is available
|
||||
at ODR rates of up to 400 Hz. FXOS8700CQ is available in a plastic QFN
|
||||
package and it is guaranteed to operate over the extended temperature
|
||||
range of –40 °C to +85 °C.
|
||||
|
||||
TODO: Trigger and IRQ configuration support
|
||||
|
||||
Datasheet:
|
||||
http://cache.freescale.com/files/sensors/doc/data_sheet/FXOS8700CQ.pdf
|
||||
|
||||
Signed-off-by: Robert Jones <rjones@gateworks.com>
|
||||
Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
|
||||
---
|
||||
drivers/iio/imu/Kconfig | 27 ++
|
||||
drivers/iio/imu/Makefile | 5 +
|
||||
drivers/iio/imu/fxos8700.h | 10 +
|
||||
drivers/iio/imu/fxos8700_core.c | 649 ++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/iio/imu/fxos8700_i2c.c | 71 +++++
|
||||
drivers/iio/imu/fxos8700_spi.c | 59 ++++
|
||||
6 files changed, 821 insertions(+)
|
||||
create mode 100644 drivers/iio/imu/fxos8700.h
|
||||
create mode 100644 drivers/iio/imu/fxos8700_core.c
|
||||
create mode 100644 drivers/iio/imu/fxos8700_i2c.c
|
||||
create mode 100644 drivers/iio/imu/fxos8700_spi.c
|
||||
|
||||
--- a/drivers/iio/imu/Kconfig
|
||||
+++ b/drivers/iio/imu/Kconfig
|
||||
@@ -40,6 +40,33 @@ config ADIS16480
|
||||
|
||||
source "drivers/iio/imu/bmi160/Kconfig"
|
||||
|
||||
+config FXOS8700
|
||||
+ tristate
|
||||
+
|
||||
+config FXOS8700_I2C
|
||||
+ tristate "NXP FXOS8700 I2C driver"
|
||||
+ depends on I2C
|
||||
+ select FXOS8700
|
||||
+ select REGMAP_I2C
|
||||
+ help
|
||||
+ Say yes here to build support for the NXP FXOS8700 m+g combo
|
||||
+ sensor on I2C.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module will be
|
||||
+ called fxos8700_i2c.
|
||||
+
|
||||
+config FXOS8700_SPI
|
||||
+ tristate "NXP FXOS8700 SPI driver"
|
||||
+ depends on SPI
|
||||
+ select FXOS8700
|
||||
+ select REGMAP_SPI
|
||||
+ help
|
||||
+ Say yes here to build support for the NXP FXOS8700 m+g combo
|
||||
+ sensor on SPI.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module will be
|
||||
+ called fxos8700_spi.
|
||||
+
|
||||
config KMX61
|
||||
tristate "Kionix KMX61 6-axis accelerometer and magnetometer"
|
||||
depends on I2C
|
||||
--- a/drivers/iio/imu/Makefile
|
||||
+++ b/drivers/iio/imu/Makefile
|
||||
@@ -14,6 +14,11 @@ adis_lib-$(CONFIG_IIO_ADIS_LIB_BUFFER) +
|
||||
obj-$(CONFIG_IIO_ADIS_LIB) += adis_lib.o
|
||||
|
||||
obj-y += bmi160/
|
||||
+
|
||||
+obj-$(CONFIG_FXOS8700) += fxos8700_core.o
|
||||
+obj-$(CONFIG_FXOS8700_I2C) += fxos8700_i2c.o
|
||||
+obj-$(CONFIG_FXOS8700_SPI) += fxos8700_spi.o
|
||||
+
|
||||
obj-y += inv_mpu6050/
|
||||
|
||||
obj-$(CONFIG_KMX61) += kmx61.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/iio/imu/fxos8700.h
|
||||
@@ -0,0 +1,10 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+#ifndef FXOS8700_H_
|
||||
+#define FXOS8700_H_
|
||||
+
|
||||
+extern const struct regmap_config fxos8700_regmap_config;
|
||||
+
|
||||
+int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
|
||||
+ const char *name, bool use_spi);
|
||||
+
|
||||
+#endif /* FXOS8700_H_ */
|
||||
--- /dev/null
|
||||
+++ b/drivers/iio/imu/fxos8700_core.c
|
||||
@@ -0,0 +1,649 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * FXOS8700 - NXP IMU (accelerometer plus magnetometer)
|
||||
+ *
|
||||
+ * IIO core driver for FXOS8700, with support for I2C/SPI busses
|
||||
+ *
|
||||
+ * TODO: Buffer, trigger, and IRQ support
|
||||
+ */
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/bitops.h>
|
||||
+
|
||||
+#include <linux/iio/iio.h>
|
||||
+#include <linux/iio/sysfs.h>
|
||||
+
|
||||
+#include "fxos8700.h"
|
||||
+
|
||||
+/* Register Definitions */
|
||||
+#define FXOS8700_STATUS 0x00
|
||||
+#define FXOS8700_OUT_X_MSB 0x01
|
||||
+#define FXOS8700_OUT_X_LSB 0x02
|
||||
+#define FXOS8700_OUT_Y_MSB 0x03
|
||||
+#define FXOS8700_OUT_Y_LSB 0x04
|
||||
+#define FXOS8700_OUT_Z_MSB 0x05
|
||||
+#define FXOS8700_OUT_Z_LSB 0x06
|
||||
+#define FXOS8700_F_SETUP 0x09
|
||||
+#define FXOS8700_TRIG_CFG 0x0a
|
||||
+#define FXOS8700_SYSMOD 0x0b
|
||||
+#define FXOS8700_INT_SOURCE 0x0c
|
||||
+#define FXOS8700_WHO_AM_I 0x0d
|
||||
+#define FXOS8700_XYZ_DATA_CFG 0x0e
|
||||
+#define FXOS8700_HP_FILTER_CUTOFF 0x0f
|
||||
+#define FXOS8700_PL_STATUS 0x10
|
||||
+#define FXOS8700_PL_CFG 0x11
|
||||
+#define FXOS8700_PL_COUNT 0x12
|
||||
+#define FXOS8700_PL_BF_ZCOMP 0x13
|
||||
+#define FXOS8700_PL_THS_REG 0x14
|
||||
+#define FXOS8700_A_FFMT_CFG 0x15
|
||||
+#define FXOS8700_A_FFMT_SRC 0x16
|
||||
+#define FXOS8700_A_FFMT_THS 0x17
|
||||
+#define FXOS8700_A_FFMT_COUNT 0x18
|
||||
+#define FXOS8700_TRANSIENT_CFG 0x1d
|
||||
+#define FXOS8700_TRANSIENT_SRC 0x1e
|
||||
+#define FXOS8700_TRANSIENT_THS 0x1f
|
||||
+#define FXOS8700_TRANSIENT_COUNT 0x20
|
||||
+#define FXOS8700_PULSE_CFG 0x21
|
||||
+#define FXOS8700_PULSE_SRC 0x22
|
||||
+#define FXOS8700_PULSE_THSX 0x23
|
||||
+#define FXOS8700_PULSE_THSY 0x24
|
||||
+#define FXOS8700_PULSE_THSZ 0x25
|
||||
+#define FXOS8700_PULSE_TMLT 0x26
|
||||
+#define FXOS8700_PULSE_LTCY 0x27
|
||||
+#define FXOS8700_PULSE_WIND 0x28
|
||||
+#define FXOS8700_ASLP_COUNT 0x29
|
||||
+#define FXOS8700_CTRL_REG1 0x2a
|
||||
+#define FXOS8700_CTRL_REG2 0x2b
|
||||
+#define FXOS8700_CTRL_REG3 0x2c
|
||||
+#define FXOS8700_CTRL_REG4 0x2d
|
||||
+#define FXOS8700_CTRL_REG5 0x2e
|
||||
+#define FXOS8700_OFF_X 0x2f
|
||||
+#define FXOS8700_OFF_Y 0x30
|
||||
+#define FXOS8700_OFF_Z 0x31
|
||||
+#define FXOS8700_M_DR_STATUS 0x32
|
||||
+#define FXOS8700_M_OUT_X_MSB 0x33
|
||||
+#define FXOS8700_M_OUT_X_LSB 0x34
|
||||
+#define FXOS8700_M_OUT_Y_MSB 0x35
|
||||
+#define FXOS8700_M_OUT_Y_LSB 0x36
|
||||
+#define FXOS8700_M_OUT_Z_MSB 0x37
|
||||
+#define FXOS8700_M_OUT_Z_LSB 0x38
|
||||
+#define FXOS8700_CMP_X_MSB 0x39
|
||||
+#define FXOS8700_CMP_X_LSB 0x3a
|
||||
+#define FXOS8700_CMP_Y_MSB 0x3b
|
||||
+#define FXOS8700_CMP_Y_LSB 0x3c
|
||||
+#define FXOS8700_CMP_Z_MSB 0x3d
|
||||
+#define FXOS8700_CMP_Z_LSB 0x3e
|
||||
+#define FXOS8700_M_OFF_X_MSB 0x3f
|
||||
+#define FXOS8700_M_OFF_X_LSB 0x40
|
||||
+#define FXOS8700_M_OFF_Y_MSB 0x41
|
||||
+#define FXOS8700_M_OFF_Y_LSB 0x42
|
||||
+#define FXOS8700_M_OFF_Z_MSB 0x43
|
||||
+#define FXOS8700_M_OFF_Z_LSB 0x44
|
||||
+#define FXOS8700_MAX_X_MSB 0x45
|
||||
+#define FXOS8700_MAX_X_LSB 0x46
|
||||
+#define FXOS8700_MAX_Y_MSB 0x47
|
||||
+#define FXOS8700_MAX_Y_LSB 0x48
|
||||
+#define FXOS8700_MAX_Z_MSB 0x49
|
||||
+#define FXOS8700_MAX_Z_LSB 0x4a
|
||||
+#define FXOS8700_MIN_X_MSB 0x4b
|
||||
+#define FXOS8700_MIN_X_LSB 0x4c
|
||||
+#define FXOS8700_MIN_Y_MSB 0x4d
|
||||
+#define FXOS8700_MIN_Y_LSB 0x4e
|
||||
+#define FXOS8700_MIN_Z_MSB 0x4f
|
||||
+#define FXOS8700_MIN_Z_LSB 0x50
|
||||
+#define FXOS8700_TEMP 0x51
|
||||
+#define FXOS8700_M_THS_CFG 0x52
|
||||
+#define FXOS8700_M_THS_SRC 0x53
|
||||
+#define FXOS8700_M_THS_X_MSB 0x54
|
||||
+#define FXOS8700_M_THS_X_LSB 0x55
|
||||
+#define FXOS8700_M_THS_Y_MSB 0x56
|
||||
+#define FXOS8700_M_THS_Y_LSB 0x57
|
||||
+#define FXOS8700_M_THS_Z_MSB 0x58
|
||||
+#define FXOS8700_M_THS_Z_LSB 0x59
|
||||
+#define FXOS8700_M_THS_COUNT 0x5a
|
||||
+#define FXOS8700_M_CTRL_REG1 0x5b
|
||||
+#define FXOS8700_M_CTRL_REG2 0x5c
|
||||
+#define FXOS8700_M_CTRL_REG3 0x5d
|
||||
+#define FXOS8700_M_INT_SRC 0x5e
|
||||
+#define FXOS8700_A_VECM_CFG 0x5f
|
||||
+#define FXOS8700_A_VECM_THS_MSB 0x60
|
||||
+#define FXOS8700_A_VECM_THS_LSB 0x61
|
||||
+#define FXOS8700_A_VECM_CNT 0x62
|
||||
+#define FXOS8700_A_VECM_INITX_MSB 0x63
|
||||
+#define FXOS8700_A_VECM_INITX_LSB 0x64
|
||||
+#define FXOS8700_A_VECM_INITY_MSB 0x65
|
||||
+#define FXOS8700_A_VECM_INITY_LSB 0x66
|
||||
+#define FXOS8700_A_VECM_INITZ_MSB 0x67
|
||||
+#define FXOS8700_A_VECM_INITZ_LSB 0x68
|
||||
+#define FXOS8700_M_VECM_CFG 0x69
|
||||
+#define FXOS8700_M_VECM_THS_MSB 0x6a
|
||||
+#define FXOS8700_M_VECM_THS_LSB 0x6b
|
||||
+#define FXOS8700_M_VECM_CNT 0x6c
|
||||
+#define FXOS8700_M_VECM_INITX_MSB 0x6d
|
||||
+#define FXOS8700_M_VECM_INITX_LSB 0x6e
|
||||
+#define FXOS8700_M_VECM_INITY_MSB 0x6f
|
||||
+#define FXOS8700_M_VECM_INITY_LSB 0x70
|
||||
+#define FXOS8700_M_VECM_INITZ_MSB 0x71
|
||||
+#define FXOS8700_M_VECM_INITZ_LSB 0x72
|
||||
+#define FXOS8700_A_FFMT_THS_X_MSB 0x73
|
||||
+#define FXOS8700_A_FFMT_THS_X_LSB 0x74
|
||||
+#define FXOS8700_A_FFMT_THS_Y_MSB 0x75
|
||||
+#define FXOS8700_A_FFMT_THS_Y_LSB 0x76
|
||||
+#define FXOS8700_A_FFMT_THS_Z_MSB 0x77
|
||||
+#define FXOS8700_A_FFMT_THS_Z_LSB 0x78
|
||||
+#define FXOS8700_A_TRAN_INIT_MSB 0x79
|
||||
+#define FXOS8700_A_TRAN_INIT_LSB_X 0x7a
|
||||
+#define FXOS8700_A_TRAN_INIT_LSB_Y 0x7b
|
||||
+#define FXOS8700_A_TRAN_INIT_LSB_Z 0x7d
|
||||
+#define FXOS8700_TM_NVM_LOCK 0x7e
|
||||
+#define FXOS8700_NVM_DATA0_35 0x80
|
||||
+#define FXOS8700_NVM_DATA_BNK3 0xa4
|
||||
+#define FXOS8700_NVM_DATA_BNK2 0xa5
|
||||
+#define FXOS8700_NVM_DATA_BNK1 0xa6
|
||||
+#define FXOS8700_NVM_DATA_BNK0 0xa7
|
||||
+
|
||||
+/* Bit definitions for FXOS8700_CTRL_REG1 */
|
||||
+#define FXOS8700_CTRL_ODR_MSK 0x38
|
||||
+#define FXOS8700_CTRL_ODR_MAX 0x00
|
||||
+#define FXOS8700_CTRL_ODR_MIN GENMASK(4, 3)
|
||||
+
|
||||
+/* Bit definitions for FXOS8700_M_CTRL_REG1 */
|
||||
+#define FXOS8700_HMS_MASK GENMASK(1, 0)
|
||||
+#define FXOS8700_OS_MASK GENMASK(4, 2)
|
||||
+
|
||||
+/* Bit definitions for FXOS8700_M_CTRL_REG2 */
|
||||
+#define FXOS8700_MAXMIN_RST BIT(2)
|
||||
+#define FXOS8700_MAXMIN_DIS_THS BIT(3)
|
||||
+#define FXOS8700_MAXMIN_DIS BIT(4)
|
||||
+
|
||||
+#define FXOS8700_ACTIVE 0x01
|
||||
+#define FXOS8700_ACTIVE_MIN_USLEEP 4000 /* from table 6 in datasheet */
|
||||
+
|
||||
+#define FXOS8700_DEVICE_ID 0xC7
|
||||
+#define FXOS8700_PRE_DEVICE_ID 0xC4
|
||||
+#define FXOS8700_DATA_BUF_SIZE 3
|
||||
+
|
||||
+struct fxos8700_data {
|
||||
+ struct regmap *regmap;
|
||||
+ struct iio_trigger *trig;
|
||||
+ __be16 buf[FXOS8700_DATA_BUF_SIZE] ____cacheline_aligned;
|
||||
+};
|
||||
+
|
||||
+/* Regmap info */
|
||||
+static const struct regmap_range read_range[] = {
|
||||
+ {
|
||||
+ .range_min = FXOS8700_STATUS,
|
||||
+ .range_max = FXOS8700_A_FFMT_COUNT,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_TRANSIENT_CFG,
|
||||
+ .range_max = FXOS8700_A_FFMT_THS_Z_LSB,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_range write_range[] = {
|
||||
+ {
|
||||
+ .range_min = FXOS8700_F_SETUP,
|
||||
+ .range_max = FXOS8700_TRIG_CFG,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_XYZ_DATA_CFG,
|
||||
+ .range_max = FXOS8700_HP_FILTER_CUTOFF,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_PL_CFG,
|
||||
+ .range_max = FXOS8700_A_FFMT_CFG,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_A_FFMT_THS,
|
||||
+ .range_max = FXOS8700_TRANSIENT_CFG,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_TRANSIENT_THS,
|
||||
+ .range_max = FXOS8700_PULSE_CFG,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_PULSE_THSX,
|
||||
+ .range_max = FXOS8700_OFF_Z,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_M_OFF_X_MSB,
|
||||
+ .range_max = FXOS8700_M_OFF_Z_LSB,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_M_THS_CFG,
|
||||
+ .range_max = FXOS8700_M_THS_CFG,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_M_THS_X_MSB,
|
||||
+ .range_max = FXOS8700_M_CTRL_REG3,
|
||||
+ }, {
|
||||
+ .range_min = FXOS8700_A_VECM_CFG,
|
||||
+ .range_max = FXOS8700_A_FFMT_THS_Z_LSB,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table driver_read_table = {
|
||||
+ .yes_ranges = read_range,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(read_range),
|
||||
+};
|
||||
+
|
||||
+static const struct regmap_access_table driver_write_table = {
|
||||
+ .yes_ranges = write_range,
|
||||
+ .n_yes_ranges = ARRAY_SIZE(write_range),
|
||||
+};
|
||||
+
|
||||
+const struct regmap_config fxos8700_regmap_config = {
|
||||
+ .reg_bits = 8,
|
||||
+ .val_bits = 8,
|
||||
+ .max_register = FXOS8700_NVM_DATA_BNK0,
|
||||
+ .rd_table = &driver_read_table,
|
||||
+ .wr_table = &driver_write_table,
|
||||
+};
|
||||
+EXPORT_SYMBOL(fxos8700_regmap_config);
|
||||
+
|
||||
+#define FXOS8700_CHANNEL(_type, _axis) { \
|
||||
+ .type = _type, \
|
||||
+ .modified = 1, \
|
||||
+ .channel2 = IIO_MOD_##_axis, \
|
||||
+ .info_mask_separate = BIT(IIO_CHAN_INFO_RAW), \
|
||||
+ .info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE) | \
|
||||
+ BIT(IIO_CHAN_INFO_SAMP_FREQ), \
|
||||
+}
|
||||
+
|
||||
+enum fxos8700_accel_scale_bits {
|
||||
+ MODE_2G = 0,
|
||||
+ MODE_4G,
|
||||
+ MODE_8G,
|
||||
+};
|
||||
+
|
||||
+/* scan indexes follow DATA register order */
|
||||
+enum fxos8700_scan_axis {
|
||||
+ FXOS8700_SCAN_ACCEL_X = 0,
|
||||
+ FXOS8700_SCAN_ACCEL_Y,
|
||||
+ FXOS8700_SCAN_ACCEL_Z,
|
||||
+ FXOS8700_SCAN_MAGN_X,
|
||||
+ FXOS8700_SCAN_MAGN_Y,
|
||||
+ FXOS8700_SCAN_MAGN_Z,
|
||||
+ FXOS8700_SCAN_RHALL,
|
||||
+ FXOS8700_SCAN_TIMESTAMP,
|
||||
+};
|
||||
+
|
||||
+enum fxos8700_sensor {
|
||||
+ FXOS8700_ACCEL = 0,
|
||||
+ FXOS8700_MAGN,
|
||||
+ FXOS8700_NUM_SENSORS /* must be last */
|
||||
+};
|
||||
+
|
||||
+enum fxos8700_int_pin {
|
||||
+ FXOS8700_PIN_INT1,
|
||||
+ FXOS8700_PIN_INT2
|
||||
+};
|
||||
+
|
||||
+struct fxos8700_scale {
|
||||
+ u8 bits;
|
||||
+ int uscale;
|
||||
+};
|
||||
+
|
||||
+struct fxos8700_odr {
|
||||
+ u8 bits;
|
||||
+ int odr;
|
||||
+ int uodr;
|
||||
+};
|
||||
+
|
||||
+static const struct fxos8700_scale fxos8700_accel_scale[] = {
|
||||
+ { MODE_2G, 244},
|
||||
+ { MODE_4G, 488},
|
||||
+ { MODE_8G, 976},
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * Accellerometer and magnetometer have the same ODR options, set in the
|
||||
+ * CTRL_REG1 register. ODR is halved when using both sensors at once in
|
||||
+ * hybrid mode.
|
||||
+ */
|
||||
+static const struct fxos8700_odr fxos8700_odr[] = {
|
||||
+ {0x00, 800, 0},
|
||||
+ {0x01, 400, 0},
|
||||
+ {0x02, 200, 0},
|
||||
+ {0x03, 100, 0},
|
||||
+ {0x04, 50, 0},
|
||||
+ {0x05, 12, 500000},
|
||||
+ {0x06, 6, 250000},
|
||||
+ {0x07, 1, 562500},
|
||||
+};
|
||||
+
|
||||
+static const struct iio_chan_spec fxos8700_channels[] = {
|
||||
+ FXOS8700_CHANNEL(IIO_ACCEL, X),
|
||||
+ FXOS8700_CHANNEL(IIO_ACCEL, Y),
|
||||
+ FXOS8700_CHANNEL(IIO_ACCEL, Z),
|
||||
+ FXOS8700_CHANNEL(IIO_MAGN, X),
|
||||
+ FXOS8700_CHANNEL(IIO_MAGN, Y),
|
||||
+ FXOS8700_CHANNEL(IIO_MAGN, Z),
|
||||
+ IIO_CHAN_SOFT_TIMESTAMP(FXOS8700_SCAN_TIMESTAMP),
|
||||
+};
|
||||
+
|
||||
+static enum fxos8700_sensor fxos8700_to_sensor(enum iio_chan_type iio_type)
|
||||
+{
|
||||
+ switch (iio_type) {
|
||||
+ case IIO_ACCEL:
|
||||
+ return FXOS8700_ACCEL;
|
||||
+ case IIO_ANGL_VEL:
|
||||
+ return FXOS8700_MAGN;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_set_active_mode(struct fxos8700_data *data,
|
||||
+ enum fxos8700_sensor t, bool mode)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, mode);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ usleep_range(FXOS8700_ACTIVE_MIN_USLEEP,
|
||||
+ FXOS8700_ACTIVE_MIN_USLEEP + 1000);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_set_scale(struct fxos8700_data *data,
|
||||
+ enum fxos8700_sensor t, int uscale)
|
||||
+{
|
||||
+ int i;
|
||||
+ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
|
||||
+ struct device *dev = regmap_get_device(data->regmap);
|
||||
+
|
||||
+ if (t == FXOS8700_MAGN) {
|
||||
+ dev_err(dev, "Magnetometer scale is locked at 1200uT\n");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < scale_num; i++)
|
||||
+ if (fxos8700_accel_scale[i].uscale == uscale)
|
||||
+ break;
|
||||
+
|
||||
+ if (i == scale_num)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG,
|
||||
+ fxos8700_accel_scale[i].bits);
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_get_scale(struct fxos8700_data *data,
|
||||
+ enum fxos8700_sensor t, int *uscale)
|
||||
+{
|
||||
+ int i, ret, val;
|
||||
+ static const int scale_num = ARRAY_SIZE(fxos8700_accel_scale);
|
||||
+
|
||||
+ if (t == FXOS8700_MAGN) {
|
||||
+ *uscale = 1200; /* Magnetometer is locked at 1200uT */
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ ret = regmap_read(data->regmap, FXOS8700_XYZ_DATA_CFG, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ for (i = 0; i < scale_num; i++) {
|
||||
+ if (fxos8700_accel_scale[i].bits == (val & 0x3)) {
|
||||
+ *uscale = fxos8700_accel_scale[i].uscale;
|
||||
+ return 0;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_get_data(struct fxos8700_data *data, int chan_type,
|
||||
+ int axis, int *val)
|
||||
+{
|
||||
+ u8 base, reg;
|
||||
+ int ret;
|
||||
+ enum fxos8700_sensor type = fxos8700_to_sensor(chan_type);
|
||||
+
|
||||
+ base = type ? FXOS8700_OUT_X_MSB : FXOS8700_M_OUT_X_MSB;
|
||||
+
|
||||
+ /* Block read 6 bytes of device output registers to avoid data loss */
|
||||
+ ret = regmap_bulk_read(data->regmap, base, data->buf,
|
||||
+ FXOS8700_DATA_BUF_SIZE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Convert axis to buffer index */
|
||||
+ reg = axis - IIO_MOD_X;
|
||||
+
|
||||
+ /* Convert to native endianness */
|
||||
+ *val = sign_extend32(be16_to_cpu(data->buf[reg]), 15);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_set_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
|
||||
+ int odr, int uodr)
|
||||
+{
|
||||
+ int i, ret, val;
|
||||
+ bool active_mode;
|
||||
+ static const int odr_num = ARRAY_SIZE(fxos8700_odr);
|
||||
+
|
||||
+ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ active_mode = val & FXOS8700_ACTIVE;
|
||||
+
|
||||
+ if (active_mode) {
|
||||
+ /*
|
||||
+ * The device must be in standby mode to change any of the
|
||||
+ * other fields within CTRL_REG1
|
||||
+ */
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
|
||||
+ val & ~FXOS8700_ACTIVE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < odr_num; i++)
|
||||
+ if (fxos8700_odr[i].odr == odr && fxos8700_odr[i].uodr == uodr)
|
||||
+ break;
|
||||
+
|
||||
+ if (i >= odr_num)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return regmap_update_bits(data->regmap,
|
||||
+ FXOS8700_CTRL_REG1,
|
||||
+ FXOS8700_CTRL_ODR_MSK + FXOS8700_ACTIVE,
|
||||
+ fxos8700_odr[i].bits << 3 | active_mode);
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_get_odr(struct fxos8700_data *data, enum fxos8700_sensor t,
|
||||
+ int *odr, int *uodr)
|
||||
+{
|
||||
+ int i, val, ret;
|
||||
+ static const int odr_num = ARRAY_SIZE(fxos8700_odr);
|
||||
+
|
||||
+ ret = regmap_read(data->regmap, FXOS8700_CTRL_REG1, &val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ val &= FXOS8700_CTRL_ODR_MSK;
|
||||
+
|
||||
+ for (i = 0; i < odr_num; i++)
|
||||
+ if (val == fxos8700_odr[i].bits)
|
||||
+ break;
|
||||
+
|
||||
+ if (i >= odr_num)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ *odr = fxos8700_odr[i].odr;
|
||||
+ *uodr = fxos8700_odr[i].uodr;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_read_raw(struct iio_dev *indio_dev,
|
||||
+ struct iio_chan_spec const *chan,
|
||||
+ int *val, int *val2, long mask)
|
||||
+{
|
||||
+ int ret;
|
||||
+ struct fxos8700_data *data = iio_priv(indio_dev);
|
||||
+
|
||||
+ switch (mask) {
|
||||
+ case IIO_CHAN_INFO_RAW:
|
||||
+ ret = fxos8700_get_data(data, chan->type, chan->channel2, val);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+ return IIO_VAL_INT;
|
||||
+ case IIO_CHAN_INFO_SCALE:
|
||||
+ *val = 0;
|
||||
+ ret = fxos8700_get_scale(data, fxos8700_to_sensor(chan->type),
|
||||
+ val2);
|
||||
+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
|
||||
+ case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
+ ret = fxos8700_get_odr(data, fxos8700_to_sensor(chan->type),
|
||||
+ val, val2);
|
||||
+ return ret ? ret : IIO_VAL_INT_PLUS_MICRO;
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static int fxos8700_write_raw(struct iio_dev *indio_dev,
|
||||
+ struct iio_chan_spec const *chan,
|
||||
+ int val, int val2, long mask)
|
||||
+{
|
||||
+ struct fxos8700_data *data = iio_priv(indio_dev);
|
||||
+
|
||||
+ switch (mask) {
|
||||
+ case IIO_CHAN_INFO_SCALE:
|
||||
+ return fxos8700_set_scale(data, fxos8700_to_sensor(chan->type),
|
||||
+ val2);
|
||||
+ case IIO_CHAN_INFO_SAMP_FREQ:
|
||||
+ return fxos8700_set_odr(data, fxos8700_to_sensor(chan->type),
|
||||
+ val, val2);
|
||||
+ default:
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static IIO_CONST_ATTR(in_accel_sampling_frequency_available,
|
||||
+ "1.5625 6.25 12.5 50 100 200 400 800");
|
||||
+static IIO_CONST_ATTR(in_magn_sampling_frequency_available,
|
||||
+ "1.5625 6.25 12.5 50 100 200 400 800");
|
||||
+static IIO_CONST_ATTR(in_accel_scale_available, "0.000244 0.000488 0.000976");
|
||||
+static IIO_CONST_ATTR(in_magn_scale_available, "0.000001200");
|
||||
+
|
||||
+static struct attribute *fxos8700_attrs[] = {
|
||||
+ &iio_const_attr_in_accel_sampling_frequency_available.dev_attr.attr,
|
||||
+ &iio_const_attr_in_magn_sampling_frequency_available.dev_attr.attr,
|
||||
+ &iio_const_attr_in_accel_scale_available.dev_attr.attr,
|
||||
+ &iio_const_attr_in_magn_scale_available.dev_attr.attr,
|
||||
+ NULL,
|
||||
+};
|
||||
+
|
||||
+static const struct attribute_group fxos8700_attrs_group = {
|
||||
+ .attrs = fxos8700_attrs,
|
||||
+};
|
||||
+
|
||||
+static const struct iio_info fxos8700_info = {
|
||||
+ .read_raw = fxos8700_read_raw,
|
||||
+ .write_raw = fxos8700_write_raw,
|
||||
+ .attrs = &fxos8700_attrs_group,
|
||||
+};
|
||||
+
|
||||
+static int fxos8700_chip_init(struct fxos8700_data *data, bool use_spi)
|
||||
+{
|
||||
+ int ret;
|
||||
+ unsigned int val;
|
||||
+ struct device *dev = regmap_get_device(data->regmap);
|
||||
+
|
||||
+ ret = regmap_read(data->regmap, FXOS8700_WHO_AM_I, &val);
|
||||
+ if (ret) {
|
||||
+ dev_err(dev, "Error reading chip id\n");
|
||||
+ return ret;
|
||||
+ }
|
||||
+ if (val != FXOS8700_DEVICE_ID && val != FXOS8700_PRE_DEVICE_ID) {
|
||||
+ dev_err(dev, "Wrong chip id, got %x expected %x or %x\n",
|
||||
+ val, FXOS8700_DEVICE_ID, FXOS8700_PRE_DEVICE_ID);
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+
|
||||
+ ret = fxos8700_set_active_mode(data, FXOS8700_ACCEL, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = fxos8700_set_active_mode(data, FXOS8700_MAGN, true);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * The device must be in standby mode to change any of the other fields
|
||||
+ * within CTRL_REG1
|
||||
+ */
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1, 0x00);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Set max oversample ratio (OSR) and both devices active */
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG1,
|
||||
+ FXOS8700_HMS_MASK | FXOS8700_OS_MASK);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Disable and rst min/max measurements & threshold */
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_M_CTRL_REG2,
|
||||
+ FXOS8700_MAXMIN_RST | FXOS8700_MAXMIN_DIS_THS |
|
||||
+ FXOS8700_MAXMIN_DIS);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Max ODR (800Hz individual or 400Hz hybrid), active mode */
|
||||
+ ret = regmap_write(data->regmap, FXOS8700_CTRL_REG1,
|
||||
+ FXOS8700_CTRL_ODR_MAX | FXOS8700_ACTIVE);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /* Set for max full-scale range (+/-8G) */
|
||||
+ return regmap_write(data->regmap, FXOS8700_XYZ_DATA_CFG, MODE_8G);
|
||||
+}
|
||||
+
|
||||
+static void fxos8700_chip_uninit(void *data)
|
||||
+{
|
||||
+ struct fxos8700_data *fxos8700_data = data;
|
||||
+
|
||||
+ fxos8700_set_active_mode(fxos8700_data, FXOS8700_ACCEL, false);
|
||||
+ fxos8700_set_active_mode(fxos8700_data, FXOS8700_MAGN, false);
|
||||
+}
|
||||
+
|
||||
+int fxos8700_core_probe(struct device *dev, struct regmap *regmap,
|
||||
+ const char *name, bool use_spi)
|
||||
+{
|
||||
+ struct iio_dev *indio_dev;
|
||||
+ struct fxos8700_data *data;
|
||||
+ int ret;
|
||||
+
|
||||
+ indio_dev = devm_iio_device_alloc(dev, sizeof(*data));
|
||||
+ if (!indio_dev)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ data = iio_priv(indio_dev);
|
||||
+ dev_set_drvdata(dev, indio_dev);
|
||||
+ data->regmap = regmap;
|
||||
+
|
||||
+ ret = fxos8700_chip_init(data, use_spi);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev, fxos8700_chip_uninit, data);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ indio_dev->dev.parent = dev;
|
||||
+ indio_dev->channels = fxos8700_channels;
|
||||
+ indio_dev->num_channels = ARRAY_SIZE(fxos8700_channels);
|
||||
+ indio_dev->name = name ? name : "fxos8700";
|
||||
+ indio_dev->modes = INDIO_DIRECT_MODE;
|
||||
+ indio_dev->info = &fxos8700_info;
|
||||
+
|
||||
+ return devm_iio_device_register(dev, indio_dev);
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(fxos8700_core_probe);
|
||||
+
|
||||
+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
+MODULE_DESCRIPTION("FXOS8700 6-Axis Acc and Mag Combo Sensor driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- /dev/null
|
||||
+++ b/drivers/iio/imu/fxos8700_i2c.c
|
||||
@@ -0,0 +1,71 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * FXOS8700 - NXP IMU, I2C bits
|
||||
+ *
|
||||
+ * 7-bit I2C slave address determined by SA1 and SA0 logic level
|
||||
+ * inputs represented in the following table:
|
||||
+ * SA1 | SA0 | Slave Address
|
||||
+ * 0 | 0 | 0x1E
|
||||
+ * 0 | 1 | 0x1D
|
||||
+ * 1 | 0 | 0x1C
|
||||
+ * 1 | 1 | 0x1F
|
||||
+ */
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/i2c.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/regmap.h>
|
||||
+
|
||||
+#include "fxos8700.h"
|
||||
+
|
||||
+static int fxos8700_i2c_probe(struct i2c_client *client,
|
||||
+ const struct i2c_device_id *id)
|
||||
+{
|
||||
+ struct regmap *regmap;
|
||||
+ const char *name = NULL;
|
||||
+
|
||||
+ regmap = devm_regmap_init_i2c(client, &fxos8700_regmap_config);
|
||||
+ if (IS_ERR(regmap)) {
|
||||
+ dev_err(&client->dev, "Failed to register i2c regmap %d\n",
|
||||
+ (int)PTR_ERR(regmap));
|
||||
+ return PTR_ERR(regmap);
|
||||
+ }
|
||||
+
|
||||
+ if (id)
|
||||
+ name = id->name;
|
||||
+
|
||||
+ return fxos8700_core_probe(&client->dev, regmap, name, false);
|
||||
+}
|
||||
+
|
||||
+static const struct i2c_device_id fxos8700_i2c_id[] = {
|
||||
+ {"fxos8700", 0},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(i2c, fxos8700_i2c_id);
|
||||
+
|
||||
+static const struct acpi_device_id fxos8700_acpi_match[] = {
|
||||
+ {"FXOS8700", 0},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
|
||||
+
|
||||
+static const struct of_device_id fxos8700_of_match[] = {
|
||||
+ { .compatible = "nxp,fxos8700" },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, fxos8700_of_match);
|
||||
+
|
||||
+static struct i2c_driver fxos8700_i2c_driver = {
|
||||
+ .driver = {
|
||||
+ .name = "fxos8700_i2c",
|
||||
+ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
|
||||
+ .of_match_table = fxos8700_of_match,
|
||||
+ },
|
||||
+ .probe = fxos8700_i2c_probe,
|
||||
+ .id_table = fxos8700_i2c_id,
|
||||
+};
|
||||
+module_i2c_driver(fxos8700_i2c_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
+MODULE_DESCRIPTION("FXOS8700 I2C driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
--- /dev/null
|
||||
+++ b/drivers/iio/imu/fxos8700_spi.c
|
||||
@@ -0,0 +1,59 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * FXOS8700 - NXP IMU, SPI bits
|
||||
+ */
|
||||
+#include <linux/acpi.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mod_devicetable.h>
|
||||
+#include <linux/regmap.h>
|
||||
+#include <linux/spi/spi.h>
|
||||
+
|
||||
+#include "fxos8700.h"
|
||||
+
|
||||
+static int fxos8700_spi_probe(struct spi_device *spi)
|
||||
+{
|
||||
+ struct regmap *regmap;
|
||||
+ const struct spi_device_id *id = spi_get_device_id(spi);
|
||||
+
|
||||
+ regmap = devm_regmap_init_spi(spi, &fxos8700_regmap_config);
|
||||
+ if (IS_ERR(regmap)) {
|
||||
+ dev_err(&spi->dev, "Failed to register spi regmap %d\n",
|
||||
+ (int)PTR_ERR(regmap));
|
||||
+ return PTR_ERR(regmap);
|
||||
+ }
|
||||
+
|
||||
+ return fxos8700_core_probe(&spi->dev, regmap, id->name, true);
|
||||
+}
|
||||
+
|
||||
+static const struct spi_device_id fxos8700_spi_id[] = {
|
||||
+ {"fxos8700", 0},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(spi, fxos8700_spi_id);
|
||||
+
|
||||
+static const struct acpi_device_id fxos8700_acpi_match[] = {
|
||||
+ {"FXOS8700", 0},
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, fxos8700_acpi_match);
|
||||
+
|
||||
+static const struct of_device_id fxos8700_of_match[] = {
|
||||
+ { .compatible = "nxp,fxos8700" },
|
||||
+ { }
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(of, fxos8700_of_match);
|
||||
+
|
||||
+static struct spi_driver fxos8700_spi_driver = {
|
||||
+ .probe = fxos8700_spi_probe,
|
||||
+ .id_table = fxos8700_spi_id,
|
||||
+ .driver = {
|
||||
+ .acpi_match_table = ACPI_PTR(fxos8700_acpi_match),
|
||||
+ .of_match_table = fxos8700_of_match,
|
||||
+ .name = "fxos8700_spi",
|
||||
+ },
|
||||
+};
|
||||
+module_spi_driver(fxos8700_spi_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Robert Jones <rjones@gateworks.com>");
|
||||
+MODULE_DESCRIPTION("FXOS8700 SPI driver");
|
||||
+MODULE_LICENSE("GPL v2");
|
||||
@ -0,0 +1,122 @@
|
||||
From d188b0675b21d5a6ca27b3e741381813983f4719 Mon Sep 17 00:00:00 2001
|
||||
From: Ryan Attard <ryanattard@ryanattard.info>
|
||||
Date: Thu, 26 Sep 2019 11:22:17 -0500
|
||||
Subject: [PATCH] scsi: core: Add sysfs attributes for VPD pages 0h and 89h
|
||||
|
||||
Add sysfs attributes for the ATA information page and Supported VPD Pages
|
||||
page.
|
||||
|
||||
Link: https://lore.kernel.org/r/20190926162216.56591-1-ryanattard@ryanattard.info
|
||||
Signed-off-by: Ryan Attard <ryanattard@ryanattard.info>
|
||||
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
|
||||
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
---
|
||||
drivers/scsi/scsi.c | 4 ++++
|
||||
drivers/scsi/scsi_sysfs.c | 19 +++++++++++++++++++
|
||||
include/scsi/scsi_device.h | 2 ++
|
||||
3 files changed, 25 insertions(+)
|
||||
|
||||
--- a/drivers/scsi/scsi.c
|
||||
+++ b/drivers/scsi/scsi.c
|
||||
@@ -465,10 +465,14 @@ void scsi_attach_vpd(struct scsi_device
|
||||
return;
|
||||
|
||||
for (i = 4; i < vpd_buf->len; i++) {
|
||||
+ if (vpd_buf->data[i] == 0x0)
|
||||
+ scsi_update_vpd_page(sdev, 0x0, &sdev->vpd_pg0);
|
||||
if (vpd_buf->data[i] == 0x80)
|
||||
scsi_update_vpd_page(sdev, 0x80, &sdev->vpd_pg80);
|
||||
if (vpd_buf->data[i] == 0x83)
|
||||
scsi_update_vpd_page(sdev, 0x83, &sdev->vpd_pg83);
|
||||
+ if (vpd_buf->data[i] == 0x89)
|
||||
+ scsi_update_vpd_page(sdev, 0x89, &sdev->vpd_pg89);
|
||||
}
|
||||
kfree(vpd_buf);
|
||||
}
|
||||
--- a/drivers/scsi/scsi_sysfs.c
|
||||
+++ b/drivers/scsi/scsi_sysfs.c
|
||||
@@ -437,6 +437,7 @@ static void scsi_device_dev_release_user
|
||||
struct device *parent;
|
||||
struct list_head *this, *tmp;
|
||||
struct scsi_vpd *vpd_pg80 = NULL, *vpd_pg83 = NULL;
|
||||
+ struct scsi_vpd *vpd_pg0 = NULL, *vpd_pg89 = NULL;
|
||||
unsigned long flags;
|
||||
|
||||
sdev = container_of(work, struct scsi_device, ew.work);
|
||||
@@ -466,16 +467,24 @@ static void scsi_device_dev_release_user
|
||||
sdev->request_queue = NULL;
|
||||
|
||||
mutex_lock(&sdev->inquiry_mutex);
|
||||
+ rcu_swap_protected(sdev->vpd_pg0, vpd_pg0,
|
||||
+ lockdep_is_held(&sdev->inquiry_mutex));
|
||||
rcu_swap_protected(sdev->vpd_pg80, vpd_pg80,
|
||||
lockdep_is_held(&sdev->inquiry_mutex));
|
||||
rcu_swap_protected(sdev->vpd_pg83, vpd_pg83,
|
||||
lockdep_is_held(&sdev->inquiry_mutex));
|
||||
+ rcu_swap_protected(sdev->vpd_pg89, vpd_pg89,
|
||||
+ lockdep_is_held(&sdev->inquiry_mutex));
|
||||
mutex_unlock(&sdev->inquiry_mutex);
|
||||
|
||||
+ if (vpd_pg0)
|
||||
+ kfree_rcu(vpd_pg0, rcu);
|
||||
if (vpd_pg83)
|
||||
kfree_rcu(vpd_pg83, rcu);
|
||||
if (vpd_pg80)
|
||||
kfree_rcu(vpd_pg80, rcu);
|
||||
+ if (vpd_pg89)
|
||||
+ kfree_rcu(vpd_pg89, rcu);
|
||||
kfree(sdev->inquiry);
|
||||
kfree(sdev);
|
||||
|
||||
@@ -868,6 +877,8 @@ static struct bin_attribute dev_attr_vpd
|
||||
|
||||
sdev_vpd_pg_attr(pg83);
|
||||
sdev_vpd_pg_attr(pg80);
|
||||
+sdev_vpd_pg_attr(pg89);
|
||||
+sdev_vpd_pg_attr(pg0);
|
||||
|
||||
static ssize_t show_inquiry(struct file *filep, struct kobject *kobj,
|
||||
struct bin_attribute *bin_attr,
|
||||
@@ -1200,12 +1211,18 @@ static umode_t scsi_sdev_bin_attr_is_vis
|
||||
struct scsi_device *sdev = to_scsi_device(dev);
|
||||
|
||||
|
||||
+ if (attr == &dev_attr_vpd_pg0 && !sdev->vpd_pg0)
|
||||
+ return 0;
|
||||
+
|
||||
if (attr == &dev_attr_vpd_pg80 && !sdev->vpd_pg80)
|
||||
return 0;
|
||||
|
||||
if (attr == &dev_attr_vpd_pg83 && !sdev->vpd_pg83)
|
||||
return 0;
|
||||
|
||||
+ if (attr == &dev_attr_vpd_pg89 && !sdev->vpd_pg89)
|
||||
+ return 0;
|
||||
+
|
||||
return S_IRUGO;
|
||||
}
|
||||
|
||||
@@ -1248,8 +1265,10 @@ static struct attribute *scsi_sdev_attrs
|
||||
};
|
||||
|
||||
static struct bin_attribute *scsi_sdev_bin_attrs[] = {
|
||||
+ &dev_attr_vpd_pg0,
|
||||
&dev_attr_vpd_pg83,
|
||||
&dev_attr_vpd_pg80,
|
||||
+ &dev_attr_vpd_pg89,
|
||||
&dev_attr_inquiry,
|
||||
NULL
|
||||
};
|
||||
--- a/include/scsi/scsi_device.h
|
||||
+++ b/include/scsi/scsi_device.h
|
||||
@@ -140,8 +140,10 @@ struct scsi_device {
|
||||
const char * rev; /* ... "nullnullnullnull" before scan */
|
||||
|
||||
#define SCSI_VPD_PG_LEN 255
|
||||
+ struct scsi_vpd __rcu *vpd_pg0;
|
||||
struct scsi_vpd __rcu *vpd_pg83;
|
||||
struct scsi_vpd __rcu *vpd_pg80;
|
||||
+ struct scsi_vpd __rcu *vpd_pg89;
|
||||
unsigned char current_tag; /* current tag */
|
||||
struct scsi_target *sdev_target; /* used only for single_lun */
|
||||
|
||||
@ -0,0 +1,737 @@
|
||||
From 5b46903d8bf372e563bf2150d46b87fff197a109 Mon Sep 17 00:00:00 2001
|
||||
From: Guenter Roeck <linux@roeck-us.net>
|
||||
Date: Thu, 28 Nov 2019 21:34:40 -0800
|
||||
Subject: [PATCH] hwmon: Driver for disk and solid state drives with
|
||||
temperature sensors
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Reading the temperature of ATA drives has been supported for years
|
||||
by userspace tools such as smarttools or hddtemp. The downside of
|
||||
such tools is that they need to run with super-user privilege, that
|
||||
the temperatures are not reported by standard tools such as 'sensors'
|
||||
or 'libsensors', and that drive temperatures are not available for use
|
||||
in the kernel's thermal subsystem.
|
||||
|
||||
This driver solves this problem by adding support for reading the
|
||||
temperature of ATA drives from the kernel using the hwmon API and
|
||||
by adding a temperature zone for each drive.
|
||||
|
||||
With this driver, the hard disk temperature can be read using the
|
||||
unprivileged 'sensors' application:
|
||||
|
||||
$ sensors drivetemp-scsi-1-0
|
||||
drivetemp-scsi-1-0
|
||||
Adapter: SCSI adapter
|
||||
temp1: +23.0°C
|
||||
|
||||
or directly from sysfs:
|
||||
|
||||
$ grep . /sys/class/hwmon/hwmon9/{name,temp1_input}
|
||||
/sys/class/hwmon/hwmon9/name:drivetemp
|
||||
/sys/class/hwmon/hwmon9/temp1_input:23000
|
||||
|
||||
If the drive supports SCT transport and reports temperature limits,
|
||||
those are reported as well.
|
||||
|
||||
drivetemp-scsi-0-0
|
||||
Adapter: SCSI adapter
|
||||
temp1: +27.0°C (low = +0.0°C, high = +60.0°C)
|
||||
(crit low = -41.0°C, crit = +85.0°C)
|
||||
(lowest = +23.0°C, highest = +34.0°C)
|
||||
|
||||
The driver attempts to use SCT Command Transport to read the drive
|
||||
temperature. If the SCT Command Transport feature set is not available,
|
||||
or if it does not report the drive temperature, drive temperatures may
|
||||
be readable through SMART attributes. Since SMART attributes are not well
|
||||
defined, this method is only used as fallback mechanism.
|
||||
|
||||
Cc: Chris Healy <cphealy@gmail.com>
|
||||
Cc: Linus Walleij <linus.walleij@linaro.org>
|
||||
Cc: Martin K. Petersen <martin.petersen@oracle.com>
|
||||
Cc: Bart Van Assche <bvanassche@acm.org>
|
||||
Reviewed-by: Linus Walleij <linus.walleij@linaro.org>
|
||||
Tested-by: Linus Walleij <linus.walleij@linaro.org>
|
||||
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
|
||||
---
|
||||
Documentation/hwmon/drivetemp.rst | 52 +++
|
||||
Documentation/hwmon/index.rst | 1 +
|
||||
drivers/hwmon/Kconfig | 10 +
|
||||
drivers/hwmon/Makefile | 1 +
|
||||
drivers/hwmon/drivetemp.c | 574 ++++++++++++++++++++++++++++++
|
||||
5 files changed, 638 insertions(+)
|
||||
create mode 100644 Documentation/hwmon/drivetemp.rst
|
||||
create mode 100644 drivers/hwmon/drivetemp.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/Documentation/hwmon/drivetemp.rst
|
||||
@@ -0,0 +1,52 @@
|
||||
+.. SPDX-License-Identifier: GPL-2.0
|
||||
+
|
||||
+Kernel driver drivetemp
|
||||
+=======================
|
||||
+
|
||||
+
|
||||
+References
|
||||
+----------
|
||||
+
|
||||
+ANS T13/1699-D
|
||||
+Information technology - AT Attachment 8 - ATA/ATAPI Command Set (ATA8-ACS)
|
||||
+
|
||||
+ANS Project T10/BSR INCITS 513
|
||||
+Information technology - SCSI Primary Commands - 4 (SPC-4)
|
||||
+
|
||||
+ANS Project INCITS 557
|
||||
+Information technology - SCSI / ATA Translation - 5 (SAT-5)
|
||||
+
|
||||
+
|
||||
+Description
|
||||
+-----------
|
||||
+
|
||||
+This driver supports reporting the temperature of disk and solid state
|
||||
+drives with temperature sensors.
|
||||
+
|
||||
+If supported, it uses the ATA SCT Command Transport feature to read
|
||||
+the current drive temperature and, if available, temperature limits
|
||||
+as well as historic minimum and maximum temperatures. If SCT Command
|
||||
+Transport is not supported, the driver uses SMART attributes to read
|
||||
+the drive temperature.
|
||||
+
|
||||
+
|
||||
+Sysfs entries
|
||||
+-------------
|
||||
+
|
||||
+Only the temp1_input attribute is always available. Other attributes are
|
||||
+available only if reported by the drive. All temperatures are reported in
|
||||
+milli-degrees Celsius.
|
||||
+
|
||||
+======================= =====================================================
|
||||
+temp1_input Current drive temperature
|
||||
+temp1_lcrit Minimum temperature limit. Operating the device below
|
||||
+ this temperature may cause physical damage to the
|
||||
+ device.
|
||||
+temp1_min Minimum recommended continuous operating limit
|
||||
+temp1_max Maximum recommended continuous operating temperature
|
||||
+temp1_crit Maximum temperature limit. Operating the device above
|
||||
+ this temperature may cause physical damage to the
|
||||
+ device.
|
||||
+temp1_lowest Minimum temperature seen this power cycle
|
||||
+temp1_highest Maximum temperature seen this power cycle
|
||||
+======================= =====================================================
|
||||
--- a/Documentation/hwmon/index.rst
|
||||
+++ b/Documentation/hwmon/index.rst
|
||||
@@ -45,6 +45,7 @@ Hardware Monitoring Kernel Drivers
|
||||
da9052
|
||||
da9055
|
||||
dme1737
|
||||
+ drivetemp
|
||||
ds1621
|
||||
ds620
|
||||
emc1403
|
||||
--- a/drivers/hwmon/Kconfig
|
||||
+++ b/drivers/hwmon/Kconfig
|
||||
@@ -385,6 +385,16 @@ config SENSORS_ATXP1
|
||||
This driver can also be built as a module. If so, the module
|
||||
will be called atxp1.
|
||||
|
||||
+config SENSORS_DRIVETEMP
|
||||
+ tristate "Hard disk drives with temperature sensors"
|
||||
+ depends on SCSI && ATA
|
||||
+ help
|
||||
+ If you say yes you get support for the temperature sensor on
|
||||
+ hard disk drives.
|
||||
+
|
||||
+ This driver can also be built as a module. If so, the module
|
||||
+ will be called satatemp.
|
||||
+
|
||||
config SENSORS_DS620
|
||||
tristate "Dallas Semiconductor DS620"
|
||||
depends on I2C
|
||||
--- a/drivers/hwmon/Makefile
|
||||
+++ b/drivers/hwmon/Makefile
|
||||
@@ -56,6 +56,7 @@ obj-$(CONFIG_SENSORS_DA9052_ADC)+= da905
|
||||
obj-$(CONFIG_SENSORS_DA9055)+= da9055-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DELL_SMM) += dell-smm-hwmon.o
|
||||
obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
|
||||
+obj-$(CONFIG_SENSORS_DRIVETEMP) += drivetemp.o
|
||||
obj-$(CONFIG_SENSORS_DS620) += ds620.o
|
||||
obj-$(CONFIG_SENSORS_DS1621) += ds1621.o
|
||||
obj-$(CONFIG_SENSORS_EMC1403) += emc1403.o
|
||||
--- /dev/null
|
||||
+++ b/drivers/hwmon/drivetemp.c
|
||||
@@ -0,0 +1,574 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Hwmon client for disk and solid state drives with temperature sensors
|
||||
+ * Copyright (C) 2019 Zodiac Inflight Innovations
|
||||
+ *
|
||||
+ * With input from:
|
||||
+ * Hwmon client for S.M.A.R.T. hard disk drives with temperature sensors.
|
||||
+ * (C) 2018 Linus Walleij
|
||||
+ *
|
||||
+ * hwmon: Driver for SCSI/ATA temperature sensors
|
||||
+ * by Constantin Baranov <const@mimas.ru>, submitted September 2009
|
||||
+ *
|
||||
+ * This drive supports reporting the temperatire of SATA drives. It can be
|
||||
+ * easily extended to report the temperature of SCSI drives.
|
||||
+ *
|
||||
+ * The primary means to read drive temperatures and temperature limits
|
||||
+ * for ATA drives is the SCT Command Transport feature set as specified in
|
||||
+ * ATA8-ACS.
|
||||
+ * It can be used to read the current drive temperature, temperature limits,
|
||||
+ * and historic minimum and maximum temperatures. The SCT Command Transport
|
||||
+ * feature set is documented in "AT Attachment 8 - ATA/ATAPI Command Set
|
||||
+ * (ATA8-ACS)".
|
||||
+ *
|
||||
+ * If the SCT Command Transport feature set is not available, drive temperatures
|
||||
+ * may be readable through SMART attributes. Since SMART attributes are not well
|
||||
+ * defined, this method is only used as fallback mechanism.
|
||||
+ *
|
||||
+ * There are three SMART attributes which may report drive temperatures.
|
||||
+ * Those are defined as follows (from
|
||||
+ * http://www.cropel.com/library/smart-attribute-list.aspx).
|
||||
+ *
|
||||
+ * 190 Temperature Temperature, monitored by a sensor somewhere inside
|
||||
+ * the drive. Raw value typicaly holds the actual
|
||||
+ * temperature (hexadecimal) in its rightmost two digits.
|
||||
+ *
|
||||
+ * 194 Temperature Temperature, monitored by a sensor somewhere inside
|
||||
+ * the drive. Raw value typicaly holds the actual
|
||||
+ * temperature (hexadecimal) in its rightmost two digits.
|
||||
+ *
|
||||
+ * 231 Temperature Temperature, monitored by a sensor somewhere inside
|
||||
+ * the drive. Raw value typicaly holds the actual
|
||||
+ * temperature (hexadecimal) in its rightmost two digits.
|
||||
+ *
|
||||
+ * Wikipedia defines attributes a bit differently.
|
||||
+ *
|
||||
+ * 190 Temperature Value is equal to (100-temp. °C), allowing manufacturer
|
||||
+ * Difference or to set a minimum threshold which corresponds to a
|
||||
+ * Airflow maximum temperature. This also follows the convention of
|
||||
+ * Temperature 100 being a best-case value and lower values being
|
||||
+ * undesirable. However, some older drives may instead
|
||||
+ * report raw Temperature (identical to 0xC2) or
|
||||
+ * Temperature minus 50 here.
|
||||
+ * 194 Temperature or Indicates the device temperature, if the appropriate
|
||||
+ * Temperature sensor is fitted. Lowest byte of the raw value contains
|
||||
+ * Celsius the exact temperature value (Celsius degrees).
|
||||
+ * 231 Life Left Indicates the approximate SSD life left, in terms of
|
||||
+ * (SSDs) or program/erase cycles or available reserved blocks.
|
||||
+ * Temperature A normalized value of 100 represents a new drive, with
|
||||
+ * a threshold value at 10 indicating a need for
|
||||
+ * replacement. A value of 0 may mean that the drive is
|
||||
+ * operating in read-only mode to allow data recovery.
|
||||
+ * Previously (pre-2010) occasionally used for Drive
|
||||
+ * Temperature (more typically reported at 0xC2).
|
||||
+ *
|
||||
+ * Common denominator is that the first raw byte reports the temperature
|
||||
+ * in degrees C on almost all drives. Some drives may report a fractional
|
||||
+ * temperature in the second raw byte.
|
||||
+ *
|
||||
+ * Known exceptions (from libatasmart):
|
||||
+ * - SAMSUNG SV0412H and SAMSUNG SV1204H) report the temperature in 10th
|
||||
+ * degrees C in the first two raw bytes.
|
||||
+ * - A few Maxtor drives report an unknown or bad value in attribute 194.
|
||||
+ * - Certain Apple SSD drives report an unknown value in attribute 190.
|
||||
+ * Only certain firmware versions are affected.
|
||||
+ *
|
||||
+ * Those exceptions affect older ATA drives and are currently ignored.
|
||||
+ * Also, the second raw byte (possibly reporting the fractional temperature)
|
||||
+ * is currently ignored.
|
||||
+ *
|
||||
+ * Many drives also report temperature limits in additional SMART data raw
|
||||
+ * bytes. The format of those is not well defined and varies widely.
|
||||
+ * The driver does not currently attempt to report those limits.
|
||||
+ *
|
||||
+ * According to data in smartmontools, attribute 231 is rarely used to report
|
||||
+ * drive temperatures. At the same time, several drives report SSD life left
|
||||
+ * in attribute 231, but do not support temperature sensors. For this reason,
|
||||
+ * attribute 231 is currently ignored.
|
||||
+ *
|
||||
+ * Following above definitions, temperatures are reported as follows.
|
||||
+ * If SCT Command Transport is supported, it is used to read the
|
||||
+ * temperature and, if available, temperature limits.
|
||||
+ * - Otherwise, if SMART attribute 194 is supported, it is used to read
|
||||
+ * the temperature.
|
||||
+ * - Otherwise, if SMART attribute 190 is supported, it is used to read
|
||||
+ * the temperature.
|
||||
+ */
|
||||
+
|
||||
+#include <linux/ata.h>
|
||||
+#include <linux/bits.h>
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/hwmon.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/list.h>
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/mutex.h>
|
||||
+#include <scsi/scsi_cmnd.h>
|
||||
+#include <scsi/scsi_device.h>
|
||||
+#include <scsi/scsi_driver.h>
|
||||
+#include <scsi/scsi_proto.h>
|
||||
+
|
||||
+struct drivetemp_data {
|
||||
+ struct list_head list; /* list of instantiated devices */
|
||||
+ struct mutex lock; /* protect data buffer accesses */
|
||||
+ struct scsi_device *sdev; /* SCSI device */
|
||||
+ struct device *dev; /* instantiating device */
|
||||
+ struct device *hwdev; /* hardware monitoring device */
|
||||
+ u8 smartdata[ATA_SECT_SIZE]; /* local buffer */
|
||||
+ int (*get_temp)(struct drivetemp_data *st, u32 attr, long *val);
|
||||
+ bool have_temp_lowest; /* lowest temp in SCT status */
|
||||
+ bool have_temp_highest; /* highest temp in SCT status */
|
||||
+ bool have_temp_min; /* have min temp */
|
||||
+ bool have_temp_max; /* have max temp */
|
||||
+ bool have_temp_lcrit; /* have lower critical limit */
|
||||
+ bool have_temp_crit; /* have critical limit */
|
||||
+ int temp_min; /* min temp */
|
||||
+ int temp_max; /* max temp */
|
||||
+ int temp_lcrit; /* lower critical limit */
|
||||
+ int temp_crit; /* critical limit */
|
||||
+};
|
||||
+
|
||||
+static LIST_HEAD(drivetemp_devlist);
|
||||
+
|
||||
+#define ATA_MAX_SMART_ATTRS 30
|
||||
+#define SMART_TEMP_PROP_190 190
|
||||
+#define SMART_TEMP_PROP_194 194
|
||||
+
|
||||
+#define SCT_STATUS_REQ_ADDR 0xe0
|
||||
+#define SCT_STATUS_VERSION_LOW 0 /* log byte offsets */
|
||||
+#define SCT_STATUS_VERSION_HIGH 1
|
||||
+#define SCT_STATUS_TEMP 200
|
||||
+#define SCT_STATUS_TEMP_LOWEST 201
|
||||
+#define SCT_STATUS_TEMP_HIGHEST 202
|
||||
+#define SCT_READ_LOG_ADDR 0xe1
|
||||
+#define SMART_READ_LOG 0xd5
|
||||
+#define SMART_WRITE_LOG 0xd6
|
||||
+
|
||||
+#define INVALID_TEMP 0x80
|
||||
+
|
||||
+#define temp_is_valid(temp) ((temp) != INVALID_TEMP)
|
||||
+#define temp_from_sct(temp) (((s8)(temp)) * 1000)
|
||||
+
|
||||
+static inline bool ata_id_smart_supported(u16 *id)
|
||||
+{
|
||||
+ return id[ATA_ID_COMMAND_SET_1] & BIT(0);
|
||||
+}
|
||||
+
|
||||
+static inline bool ata_id_smart_enabled(u16 *id)
|
||||
+{
|
||||
+ return id[ATA_ID_CFS_ENABLE_1] & BIT(0);
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_scsi_command(struct drivetemp_data *st,
|
||||
+ u8 ata_command, u8 feature,
|
||||
+ u8 lba_low, u8 lba_mid, u8 lba_high)
|
||||
+{
|
||||
+ u8 scsi_cmd[MAX_COMMAND_SIZE];
|
||||
+ int data_dir;
|
||||
+
|
||||
+ memset(scsi_cmd, 0, sizeof(scsi_cmd));
|
||||
+ scsi_cmd[0] = ATA_16;
|
||||
+ if (ata_command == ATA_CMD_SMART && feature == SMART_WRITE_LOG) {
|
||||
+ scsi_cmd[1] = (5 << 1); /* PIO Data-out */
|
||||
+ /*
|
||||
+ * No off.line or cc, write to dev, block count in sector count
|
||||
+ * field.
|
||||
+ */
|
||||
+ scsi_cmd[2] = 0x06;
|
||||
+ data_dir = DMA_TO_DEVICE;
|
||||
+ } else {
|
||||
+ scsi_cmd[1] = (4 << 1); /* PIO Data-in */
|
||||
+ /*
|
||||
+ * No off.line or cc, read from dev, block count in sector count
|
||||
+ * field.
|
||||
+ */
|
||||
+ scsi_cmd[2] = 0x0e;
|
||||
+ data_dir = DMA_FROM_DEVICE;
|
||||
+ }
|
||||
+ scsi_cmd[4] = feature;
|
||||
+ scsi_cmd[6] = 1; /* 1 sector */
|
||||
+ scsi_cmd[8] = lba_low;
|
||||
+ scsi_cmd[10] = lba_mid;
|
||||
+ scsi_cmd[12] = lba_high;
|
||||
+ scsi_cmd[14] = ata_command;
|
||||
+
|
||||
+ return scsi_execute_req(st->sdev, scsi_cmd, data_dir,
|
||||
+ st->smartdata, ATA_SECT_SIZE, NULL, HZ, 5,
|
||||
+ NULL);
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_ata_command(struct drivetemp_data *st, u8 feature,
|
||||
+ u8 select)
|
||||
+{
|
||||
+ return drivetemp_scsi_command(st, ATA_CMD_SMART, feature, select,
|
||||
+ ATA_SMART_LBAM_PASS, ATA_SMART_LBAH_PASS);
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_get_smarttemp(struct drivetemp_data *st, u32 attr,
|
||||
+ long *temp)
|
||||
+{
|
||||
+ u8 *buf = st->smartdata;
|
||||
+ bool have_temp = false;
|
||||
+ u8 temp_raw;
|
||||
+ u8 csum;
|
||||
+ int err;
|
||||
+ int i;
|
||||
+
|
||||
+ err = drivetemp_ata_command(st, ATA_SMART_READ_VALUES, 0);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ /* Checksum the read value table */
|
||||
+ csum = 0;
|
||||
+ for (i = 0; i < ATA_SECT_SIZE; i++)
|
||||
+ csum += buf[i];
|
||||
+ if (csum) {
|
||||
+ dev_dbg(&st->sdev->sdev_gendev,
|
||||
+ "checksum error reading SMART values\n");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ for (i = 0; i < ATA_MAX_SMART_ATTRS; i++) {
|
||||
+ u8 *attr = buf + i * 12;
|
||||
+ int id = attr[2];
|
||||
+
|
||||
+ if (!id)
|
||||
+ continue;
|
||||
+
|
||||
+ if (id == SMART_TEMP_PROP_190) {
|
||||
+ temp_raw = attr[7];
|
||||
+ have_temp = true;
|
||||
+ }
|
||||
+ if (id == SMART_TEMP_PROP_194) {
|
||||
+ temp_raw = attr[7];
|
||||
+ have_temp = true;
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (have_temp) {
|
||||
+ *temp = temp_raw * 1000;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ return -ENXIO;
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_get_scttemp(struct drivetemp_data *st, u32 attr, long *val)
|
||||
+{
|
||||
+ u8 *buf = st->smartdata;
|
||||
+ int err;
|
||||
+
|
||||
+ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+ switch (attr) {
|
||||
+ case hwmon_temp_input:
|
||||
+ *val = temp_from_sct(buf[SCT_STATUS_TEMP]);
|
||||
+ break;
|
||||
+ case hwmon_temp_lowest:
|
||||
+ *val = temp_from_sct(buf[SCT_STATUS_TEMP_LOWEST]);
|
||||
+ break;
|
||||
+ case hwmon_temp_highest:
|
||||
+ *val = temp_from_sct(buf[SCT_STATUS_TEMP_HIGHEST]);
|
||||
+ break;
|
||||
+ default:
|
||||
+ err = -EINVAL;
|
||||
+ break;
|
||||
+ }
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_identify_sata(struct drivetemp_data *st)
|
||||
+{
|
||||
+ struct scsi_device *sdev = st->sdev;
|
||||
+ u8 *buf = st->smartdata;
|
||||
+ struct scsi_vpd *vpd;
|
||||
+ bool is_ata, is_sata;
|
||||
+ bool have_sct_data_table;
|
||||
+ bool have_sct_temp;
|
||||
+ bool have_smart;
|
||||
+ bool have_sct;
|
||||
+ u16 *ata_id;
|
||||
+ u16 version;
|
||||
+ long temp;
|
||||
+ int err;
|
||||
+
|
||||
+ /* SCSI-ATA Translation present? */
|
||||
+ rcu_read_lock();
|
||||
+ vpd = rcu_dereference(sdev->vpd_pg89);
|
||||
+
|
||||
+ /*
|
||||
+ * Verify that ATA IDENTIFY DEVICE data is included in ATA Information
|
||||
+ * VPD and that the drive implements the SATA protocol.
|
||||
+ */
|
||||
+ if (!vpd || vpd->len < 572 || vpd->data[56] != ATA_CMD_ID_ATA ||
|
||||
+ vpd->data[36] != 0x34) {
|
||||
+ rcu_read_unlock();
|
||||
+ return -ENODEV;
|
||||
+ }
|
||||
+ ata_id = (u16 *)&vpd->data[60];
|
||||
+ is_ata = ata_id_is_ata(ata_id);
|
||||
+ is_sata = ata_id_is_sata(ata_id);
|
||||
+ have_sct = ata_id_sct_supported(ata_id);
|
||||
+ have_sct_data_table = ata_id_sct_data_tables(ata_id);
|
||||
+ have_smart = ata_id_smart_supported(ata_id) &&
|
||||
+ ata_id_smart_enabled(ata_id);
|
||||
+
|
||||
+ rcu_read_unlock();
|
||||
+
|
||||
+ /* bail out if this is not a SATA device */
|
||||
+ if (!is_ata || !is_sata)
|
||||
+ return -ENODEV;
|
||||
+ if (!have_sct)
|
||||
+ goto skip_sct;
|
||||
+
|
||||
+ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_STATUS_REQ_ADDR);
|
||||
+ if (err)
|
||||
+ goto skip_sct;
|
||||
+
|
||||
+ version = (buf[SCT_STATUS_VERSION_HIGH] << 8) |
|
||||
+ buf[SCT_STATUS_VERSION_LOW];
|
||||
+ if (version != 2 && version != 3)
|
||||
+ goto skip_sct;
|
||||
+
|
||||
+ have_sct_temp = temp_is_valid(buf[SCT_STATUS_TEMP]);
|
||||
+ if (!have_sct_temp)
|
||||
+ goto skip_sct;
|
||||
+
|
||||
+ st->have_temp_lowest = temp_is_valid(buf[SCT_STATUS_TEMP_LOWEST]);
|
||||
+ st->have_temp_highest = temp_is_valid(buf[SCT_STATUS_TEMP_HIGHEST]);
|
||||
+
|
||||
+ if (!have_sct_data_table)
|
||||
+ goto skip_sct;
|
||||
+
|
||||
+ /* Request and read temperature history table */
|
||||
+ memset(buf, '\0', sizeof(st->smartdata));
|
||||
+ buf[0] = 5; /* data table command */
|
||||
+ buf[2] = 1; /* read table */
|
||||
+ buf[4] = 2; /* temperature history table */
|
||||
+
|
||||
+ err = drivetemp_ata_command(st, SMART_WRITE_LOG, SCT_STATUS_REQ_ADDR);
|
||||
+ if (err)
|
||||
+ goto skip_sct_data;
|
||||
+
|
||||
+ err = drivetemp_ata_command(st, SMART_READ_LOG, SCT_READ_LOG_ADDR);
|
||||
+ if (err)
|
||||
+ goto skip_sct_data;
|
||||
+
|
||||
+ /*
|
||||
+ * Temperature limits per AT Attachment 8 -
|
||||
+ * ATA/ATAPI Command Set (ATA8-ACS)
|
||||
+ */
|
||||
+ st->have_temp_max = temp_is_valid(buf[6]);
|
||||
+ st->have_temp_crit = temp_is_valid(buf[7]);
|
||||
+ st->have_temp_min = temp_is_valid(buf[8]);
|
||||
+ st->have_temp_lcrit = temp_is_valid(buf[9]);
|
||||
+
|
||||
+ st->temp_max = temp_from_sct(buf[6]);
|
||||
+ st->temp_crit = temp_from_sct(buf[7]);
|
||||
+ st->temp_min = temp_from_sct(buf[8]);
|
||||
+ st->temp_lcrit = temp_from_sct(buf[9]);
|
||||
+
|
||||
+skip_sct_data:
|
||||
+ if (have_sct_temp) {
|
||||
+ st->get_temp = drivetemp_get_scttemp;
|
||||
+ return 0;
|
||||
+ }
|
||||
+skip_sct:
|
||||
+ if (!have_smart)
|
||||
+ return -ENODEV;
|
||||
+ st->get_temp = drivetemp_get_smarttemp;
|
||||
+ return drivetemp_get_smarttemp(st, hwmon_temp_input, &temp);
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_identify(struct drivetemp_data *st)
|
||||
+{
|
||||
+ struct scsi_device *sdev = st->sdev;
|
||||
+
|
||||
+ /* Bail out immediately if there is no inquiry data */
|
||||
+ if (!sdev->inquiry || sdev->inquiry_len < 16)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ /* Disk device? */
|
||||
+ if (sdev->type != TYPE_DISK && sdev->type != TYPE_ZBC)
|
||||
+ return -ENODEV;
|
||||
+
|
||||
+ return drivetemp_identify_sata(st);
|
||||
+}
|
||||
+
|
||||
+static int drivetemp_read(struct device *dev, enum hwmon_sensor_types type,
|
||||
+ u32 attr, int channel, long *val)
|
||||
+{
|
||||
+ struct drivetemp_data *st = dev_get_drvdata(dev);
|
||||
+ int err = 0;
|
||||
+
|
||||
+ if (type != hwmon_temp)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ switch (attr) {
|
||||
+ case hwmon_temp_input:
|
||||
+ case hwmon_temp_lowest:
|
||||
+ case hwmon_temp_highest:
|
||||
+ mutex_lock(&st->lock);
|
||||
+ err = st->get_temp(st, attr, val);
|
||||
+ mutex_unlock(&st->lock);
|
||||
+ break;
|
||||
+ case hwmon_temp_lcrit:
|
||||
+ *val = st->temp_lcrit;
|
||||
+ break;
|
||||
+ case hwmon_temp_min:
|
||||
+ *val = st->temp_min;
|
||||
+ break;
|
||||
+ case hwmon_temp_max:
|
||||
+ *val = st->temp_max;
|
||||
+ break;
|
||||
+ case hwmon_temp_crit:
|
||||
+ *val = st->temp_crit;
|
||||
+ break;
|
||||
+ default:
|
||||
+ err = -EINVAL;
|
||||
+ break;
|
||||
+ }
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static umode_t drivetemp_is_visible(const void *data,
|
||||
+ enum hwmon_sensor_types type,
|
||||
+ u32 attr, int channel)
|
||||
+{
|
||||
+ const struct drivetemp_data *st = data;
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case hwmon_temp:
|
||||
+ switch (attr) {
|
||||
+ case hwmon_temp_input:
|
||||
+ return 0444;
|
||||
+ case hwmon_temp_lowest:
|
||||
+ if (st->have_temp_lowest)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ case hwmon_temp_highest:
|
||||
+ if (st->have_temp_highest)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ case hwmon_temp_min:
|
||||
+ if (st->have_temp_min)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ case hwmon_temp_max:
|
||||
+ if (st->have_temp_max)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ case hwmon_temp_lcrit:
|
||||
+ if (st->have_temp_lcrit)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ case hwmon_temp_crit:
|
||||
+ if (st->have_temp_crit)
|
||||
+ return 0444;
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct hwmon_channel_info *drivetemp_info[] = {
|
||||
+ HWMON_CHANNEL_INFO(chip,
|
||||
+ HWMON_C_REGISTER_TZ),
|
||||
+ HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT |
|
||||
+ HWMON_T_LOWEST | HWMON_T_HIGHEST |
|
||||
+ HWMON_T_MIN | HWMON_T_MAX |
|
||||
+ HWMON_T_LCRIT | HWMON_T_CRIT),
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+static const struct hwmon_ops drivetemp_ops = {
|
||||
+ .is_visible = drivetemp_is_visible,
|
||||
+ .read = drivetemp_read,
|
||||
+};
|
||||
+
|
||||
+static const struct hwmon_chip_info drivetemp_chip_info = {
|
||||
+ .ops = &drivetemp_ops,
|
||||
+ .info = drivetemp_info,
|
||||
+};
|
||||
+
|
||||
+/*
|
||||
+ * The device argument points to sdev->sdev_dev. Its parent is
|
||||
+ * sdev->sdev_gendev, which we can use to get the scsi_device pointer.
|
||||
+ */
|
||||
+static int drivetemp_add(struct device *dev, struct class_interface *intf)
|
||||
+{
|
||||
+ struct scsi_device *sdev = to_scsi_device(dev->parent);
|
||||
+ struct drivetemp_data *st;
|
||||
+ int err;
|
||||
+
|
||||
+ st = kzalloc(sizeof(*st), GFP_KERNEL);
|
||||
+ if (!st)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ st->sdev = sdev;
|
||||
+ st->dev = dev;
|
||||
+ mutex_init(&st->lock);
|
||||
+
|
||||
+ if (drivetemp_identify(st)) {
|
||||
+ err = -ENODEV;
|
||||
+ goto abort;
|
||||
+ }
|
||||
+
|
||||
+ st->hwdev = hwmon_device_register_with_info(dev->parent, "drivetemp",
|
||||
+ st, &drivetemp_chip_info,
|
||||
+ NULL);
|
||||
+ if (IS_ERR(st->hwdev)) {
|
||||
+ err = PTR_ERR(st->hwdev);
|
||||
+ goto abort;
|
||||
+ }
|
||||
+
|
||||
+ list_add(&st->list, &drivetemp_devlist);
|
||||
+ return 0;
|
||||
+
|
||||
+abort:
|
||||
+ kfree(st);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static void drivetemp_remove(struct device *dev, struct class_interface *intf)
|
||||
+{
|
||||
+ struct drivetemp_data *st, *tmp;
|
||||
+
|
||||
+ list_for_each_entry_safe(st, tmp, &drivetemp_devlist, list) {
|
||||
+ if (st->dev == dev) {
|
||||
+ list_del(&st->list);
|
||||
+ hwmon_device_unregister(st->hwdev);
|
||||
+ kfree(st);
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static struct class_interface drivetemp_interface = {
|
||||
+ .add_dev = drivetemp_add,
|
||||
+ .remove_dev = drivetemp_remove,
|
||||
+};
|
||||
+
|
||||
+static int __init drivetemp_init(void)
|
||||
+{
|
||||
+ return scsi_register_interface(&drivetemp_interface);
|
||||
+}
|
||||
+
|
||||
+static void __exit drivetemp_exit(void)
|
||||
+{
|
||||
+ scsi_unregister_interface(&drivetemp_interface);
|
||||
+}
|
||||
+
|
||||
+module_init(drivetemp_init);
|
||||
+module_exit(drivetemp_exit);
|
||||
+
|
||||
+MODULE_AUTHOR("Guenter Roeck <linus@roeck-us.net>");
|
||||
+MODULE_DESCRIPTION("Hard drive temperature monitor");
|
||||
+MODULE_LICENSE("GPL");
|
||||
@ -0,0 +1,36 @@
|
||||
From 7a349e8c535d7327bf80710323c725df47149b8d Mon Sep 17 00:00:00 2001
|
||||
From: Jean-Jacques Hiblot <jjhiblot@ti.com>
|
||||
Date: Sun, 5 Jan 2020 23:31:14 +0100
|
||||
Subject: [PATCH] leds: populate the device's of_node
|
||||
|
||||
If initialization data is available and its fwnode is actually a
|
||||
of_node, store this information in the led device's structure. This
|
||||
will allow the device to use or provide OF-based API such (devm_xxx).
|
||||
|
||||
Signed-off-by: Jean-Jacques Hiblot <jjhiblot@ti.com>
|
||||
Signed-off-by: Pavel Machek <pavel@ucw.cz>
|
||||
[backport to 5.4]
|
||||
---
|
||||
|
||||
--- a/drivers/leds/led-class.c
|
||||
+++ b/drivers/leds/led-class.c
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/timer.h>
|
||||
#include <uapi/linux/uleds.h>
|
||||
+#include <linux/of.h>
|
||||
#include "leds.h"
|
||||
|
||||
static struct class *leds_class;
|
||||
@@ -276,8 +277,10 @@ int led_classdev_register_ext(struct dev
|
||||
mutex_unlock(&led_cdev->led_access);
|
||||
return PTR_ERR(led_cdev->dev);
|
||||
}
|
||||
- if (init_data && init_data->fwnode)
|
||||
+ if (init_data && init_data->fwnode) {
|
||||
led_cdev->dev->fwnode = init_data->fwnode;
|
||||
+ led_cdev->dev->of_node = to_of_node(init_data->fwnode);
|
||||
+ }
|
||||
|
||||
if (ret)
|
||||
dev_warn(parent, "Led %s renamed to %s due to name collision",
|
||||
6499
target/linux/generic/config-5.4
Normal file
6499
target/linux/generic/config-5.4
Normal file
File diff suppressed because it is too large
Load Diff
204
target/linux/generic/hack-5.4/204-module_strip.patch
Normal file
204
target/linux/generic/hack-5.4/204-module_strip.patch
Normal file
@ -0,0 +1,204 @@
|
||||
From a779a482fb9b9f8fcdf8b2519c789b4b9bb5dd05 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 16:56:48 +0200
|
||||
Subject: build: add a hack for removing non-essential module info
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/module.h | 13 ++++++++-----
|
||||
include/linux/moduleparam.h | 15 ++++++++++++---
|
||||
init/Kconfig | 7 +++++++
|
||||
kernel/module.c | 5 ++++-
|
||||
scripts/mod/modpost.c | 12 ++++++++++++
|
||||
5 files changed, 43 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/include/linux/module.h
|
||||
+++ b/include/linux/module.h
|
||||
@@ -157,6 +157,7 @@ extern void cleanup_module(void);
|
||||
|
||||
/* Generic info of form tag = "info" */
|
||||
#define MODULE_INFO(tag, info) __MODULE_INFO(tag, tag, info)
|
||||
+#define MODULE_INFO_STRIP(tag, info) __MODULE_INFO_STRIP(tag, tag, info)
|
||||
|
||||
/* For userspace: you can also call me... */
|
||||
#define MODULE_ALIAS(_alias) MODULE_INFO(alias, _alias)
|
||||
@@ -216,12 +217,12 @@ extern void cleanup_module(void);
|
||||
* Author(s), use "Name <email>" or just "Name", for multiple
|
||||
* authors use multiple MODULE_AUTHOR() statements/lines.
|
||||
*/
|
||||
-#define MODULE_AUTHOR(_author) MODULE_INFO(author, _author)
|
||||
+#define MODULE_AUTHOR(_author) MODULE_INFO_STRIP(author, _author)
|
||||
|
||||
/* What your module does. */
|
||||
-#define MODULE_DESCRIPTION(_description) MODULE_INFO(description, _description)
|
||||
+#define MODULE_DESCRIPTION(_description) MODULE_INFO_STRIP(description, _description)
|
||||
|
||||
-#ifdef MODULE
|
||||
+#if defined(MODULE) && !defined(CONFIG_MODULE_STRIPPED)
|
||||
/* Creates an alias so file2alias.c can find device table. */
|
||||
#define MODULE_DEVICE_TABLE(type, name) \
|
||||
extern typeof(name) __mod_##type##__##name##_device_table \
|
||||
@@ -248,7 +249,9 @@ extern typeof(name) __mod_##type##__##na
|
||||
*/
|
||||
|
||||
#if defined(MODULE) || !defined(CONFIG_SYSFS)
|
||||
-#define MODULE_VERSION(_version) MODULE_INFO(version, _version)
|
||||
+#define MODULE_VERSION(_version) MODULE_INFO_STRIP(version, _version)
|
||||
+#elif defined(CONFIG_MODULE_STRIPPED)
|
||||
+#define MODULE_VERSION(_version) __MODULE_INFO_DISABLED(version)
|
||||
#else
|
||||
#define MODULE_VERSION(_version) \
|
||||
MODULE_INFO(version, _version); \
|
||||
@@ -271,7 +274,7 @@ extern typeof(name) __mod_##type##__##na
|
||||
/* Optional firmware file (or files) needed by the module
|
||||
* format is simply firmware file name. Multiple firmware
|
||||
* files require multiple MODULE_FIRMWARE() specifiers */
|
||||
-#define MODULE_FIRMWARE(_firmware) MODULE_INFO(firmware, _firmware)
|
||||
+#define MODULE_FIRMWARE(_firmware) MODULE_INFO_STRIP(firmware, _firmware)
|
||||
|
||||
#define MODULE_IMPORT_NS(ns) MODULE_INFO(import_ns, #ns)
|
||||
|
||||
--- a/include/linux/moduleparam.h
|
||||
+++ b/include/linux/moduleparam.h
|
||||
@@ -20,10 +20,24 @@
|
||||
/* Chosen so that structs with an unsigned long line up. */
|
||||
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
|
||||
|
||||
+/* This struct is here for syntactic coherency, it is not used */
|
||||
+#define __MODULE_INFO_DISABLED(name) \
|
||||
+ struct __UNIQUE_ID(name) {}
|
||||
+
|
||||
+#ifdef CONFIG_MODULE_STRIPPED
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
+#else
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
|
||||
+#endif
|
||||
+
|
||||
+#ifdef MODULE
|
||||
#define __MODULE_INFO(tag, name, info) \
|
||||
static const char __UNIQUE_ID(name)[] \
|
||||
__used __attribute__((section(".modinfo"), unused, aligned(1))) \
|
||||
= __MODULE_INFO_PREFIX __stringify(tag) "=" info
|
||||
+#else
|
||||
+#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
+#endif
|
||||
|
||||
#define __MODULE_PARM_TYPE(name, _type) \
|
||||
__MODULE_INFO(parmtype, name##type, #name ":" _type)
|
||||
@@ -31,7 +45,7 @@ static const char __UNIQUE_ID(name)[]
|
||||
/* One for each parameter, describing how to use it. Some files do
|
||||
multiple of these per line, so can't just use MODULE_INFO. */
|
||||
#define MODULE_PARM_DESC(_parm, desc) \
|
||||
- __MODULE_INFO(parm, _parm, #_parm ":" desc)
|
||||
+ __MODULE_INFO_STRIP(parm, _parm, #_parm ":" desc)
|
||||
|
||||
struct kernel_param;
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -2213,6 +2213,13 @@ config TRIM_UNUSED_KSYMS
|
||||
|
||||
If unsure, or if you need to build out-of-tree modules, say N.
|
||||
|
||||
+config MODULE_STRIPPED
|
||||
+ bool "Reduce module size"
|
||||
+ depends on MODULES
|
||||
+ help
|
||||
+ Remove module parameter descriptions, author info, version, aliases,
|
||||
+ device tables, etc.
|
||||
+
|
||||
endif # MODULES
|
||||
|
||||
config MODULES_TREE_LOOKUP
|
||||
--- a/kernel/module.c
|
||||
+++ b/kernel/module.c
|
||||
@@ -3107,9 +3107,11 @@ static int setup_load_info(struct load_i
|
||||
|
||||
static int check_modinfo(struct module *mod, struct load_info *info, int flags)
|
||||
{
|
||||
- const char *modmagic = get_modinfo(info, "vermagic");
|
||||
int err;
|
||||
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
+ const char *modmagic = get_modinfo(info, "vermagic");
|
||||
+
|
||||
if (flags & MODULE_INIT_IGNORE_VERMAGIC)
|
||||
modmagic = NULL;
|
||||
|
||||
@@ -3130,6 +3132,7 @@ static int check_modinfo(struct module *
|
||||
mod->name);
|
||||
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
|
||||
}
|
||||
+#endif
|
||||
|
||||
check_modinfo_retpoline(mod, info);
|
||||
|
||||
--- a/scripts/mod/modpost.c
|
||||
+++ b/scripts/mod/modpost.c
|
||||
@@ -2056,7 +2056,9 @@ static void read_symbols(const char *mod
|
||||
symname = remove_dot(info.strtab + sym->st_name);
|
||||
|
||||
handle_modversions(mod, &info, sym, symname);
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
handle_moddevtable(mod, &info, sym, symname);
|
||||
+#endif
|
||||
}
|
||||
|
||||
/* Apply symbol namespaces from __kstrtabns_<symbol> entries. */
|
||||
@@ -2270,8 +2272,10 @@ static void add_header(struct buffer *b,
|
||||
buf_printf(b, "\n");
|
||||
buf_printf(b, "BUILD_SALT;\n");
|
||||
buf_printf(b, "\n");
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\n");
|
||||
buf_printf(b, "MODULE_INFO(name, KBUILD_MODNAME);\n");
|
||||
+#endif
|
||||
buf_printf(b, "\n");
|
||||
buf_printf(b, "__visible struct module __this_module\n");
|
||||
buf_printf(b, "__section(.gnu.linkonce.this_module) = {\n");
|
||||
@@ -2288,8 +2292,10 @@ static void add_header(struct buffer *b,
|
||||
|
||||
static void add_intree_flag(struct buffer *b, int is_intree)
|
||||
{
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
if (is_intree)
|
||||
buf_printf(b, "\nMODULE_INFO(intree, \"Y\");\n");
|
||||
+#endif
|
||||
}
|
||||
|
||||
/* Cannot check for assembler */
|
||||
@@ -2302,8 +2308,10 @@ static void add_retpoline(struct buffer
|
||||
|
||||
static void add_staging_flag(struct buffer *b, const char *name)
|
||||
{
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
if (strstarts(name, "drivers/staging"))
|
||||
buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
|
||||
+#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2387,11 +2395,13 @@ static void add_depends(struct buffer *b
|
||||
|
||||
static void add_srcversion(struct buffer *b, struct module *mod)
|
||||
{
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
if (mod->srcversion[0]) {
|
||||
buf_printf(b, "\n");
|
||||
buf_printf(b, "MODULE_INFO(srcversion, \"%s\");\n",
|
||||
mod->srcversion);
|
||||
}
|
||||
+#endif
|
||||
}
|
||||
|
||||
static void write_if_changed(struct buffer *b, const char *fname)
|
||||
@@ -2661,7 +2671,9 @@ int main(int argc, char **argv)
|
||||
add_staging_flag(&buf, mod->name);
|
||||
err |= add_versions(&buf, mod);
|
||||
add_depends(&buf, mod);
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
add_moddevtable(&buf, mod);
|
||||
+#endif
|
||||
add_srcversion(&buf, mod);
|
||||
|
||||
sprintf(fname, "%s.mod.c", mod->name);
|
||||
3053
target/linux/generic/hack-5.4/210-darwin_scripts_include.patch
Normal file
3053
target/linux/generic/hack-5.4/210-darwin_scripts_include.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
||||
From e44fc2af1ddc452b6659d08c16973d65c73b7d0a Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Date: Wed, 5 Feb 2020 18:36:43 +0000
|
||||
Subject: [PATCH] file2alias: build on macos
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
scripts/mod/file2alias.c | 3 +++
|
||||
1 file changed, 3 insertions(+)
|
||||
|
||||
--- a/scripts/mod/file2alias.c
|
||||
+++ b/scripts/mod/file2alias.c
|
||||
@@ -38,6 +38,9 @@ typedef struct {
|
||||
__u8 b[16];
|
||||
} guid_t;
|
||||
|
||||
+#ifdef __APPLE__
|
||||
+#define uuid_t compat_uuid_t
|
||||
+#endif
|
||||
/* backwards compatibility, don't use in new code */
|
||||
typedef struct {
|
||||
__u8 b[16];
|
||||
@ -0,0 +1,65 @@
|
||||
From 48232d3d931c95953ce2ddfe7da7bb164aef6a73 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:03:16 +0200
|
||||
Subject: linux-3.6: fix portability of some includes files in tools/ used on the host
|
||||
|
||||
lede-commit: 6040b1d29ab1f047c5e49b748abcb6a3196add28
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
tools/include/tools/be_byteshift.h | 4 ++++
|
||||
tools/include/tools/le_byteshift.h | 4 ++++
|
||||
tools/include/tools/linux_types.h | 22 ++++++++++++++++++++++
|
||||
3 files changed, 30 insertions(+)
|
||||
create mode 100644 tools/include/tools/linux_types.h
|
||||
|
||||
--- a/tools/include/tools/be_byteshift.h
|
||||
+++ b/tools/include/tools/be_byteshift.h
|
||||
@@ -2,6 +2,10 @@
|
||||
#ifndef _TOOLS_BE_BYTESHIFT_H
|
||||
#define _TOOLS_BE_BYTESHIFT_H
|
||||
|
||||
+#ifndef __linux__
|
||||
+#include "linux_types.h"
|
||||
+#endif
|
||||
+
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint16_t __get_unaligned_be16(const uint8_t *p)
|
||||
--- a/tools/include/tools/le_byteshift.h
|
||||
+++ b/tools/include/tools/le_byteshift.h
|
||||
@@ -2,6 +2,10 @@
|
||||
#ifndef _TOOLS_LE_BYTESHIFT_H
|
||||
#define _TOOLS_LE_BYTESHIFT_H
|
||||
|
||||
+#ifndef __linux__
|
||||
+#include "linux_types.h"
|
||||
+#endif
|
||||
+
|
||||
#include <stdint.h>
|
||||
|
||||
static inline uint16_t __get_unaligned_le16(const uint8_t *p)
|
||||
--- /dev/null
|
||||
+++ b/tools/include/tools/linux_types.h
|
||||
@@ -0,0 +1,22 @@
|
||||
+#ifndef __LINUX_TYPES_H
|
||||
+#define __LINUX_TYPES_H
|
||||
+
|
||||
+#include <stdint.h>
|
||||
+
|
||||
+typedef uint8_t __u8;
|
||||
+typedef uint8_t __be8;
|
||||
+typedef uint8_t __le8;
|
||||
+
|
||||
+typedef uint16_t __u16;
|
||||
+typedef uint16_t __be16;
|
||||
+typedef uint16_t __le16;
|
||||
+
|
||||
+typedef uint32_t __u32;
|
||||
+typedef uint32_t __be32;
|
||||
+typedef uint32_t __le32;
|
||||
+
|
||||
+typedef uint64_t __u64;
|
||||
+typedef uint64_t __be64;
|
||||
+typedef uint64_t __le64;
|
||||
+
|
||||
+#endif
|
||||
24
target/linux/generic/hack-5.4/214-spidev_h_portability.patch
Normal file
24
target/linux/generic/hack-5.4/214-spidev_h_portability.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From be9be95ff10e16a5b4ad36f903978d0cc5747024 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:04:08 +0200
|
||||
Subject: kernel: fix linux/spi/spidev.h portability issues with musl
|
||||
|
||||
Felix will try to get this define included into musl
|
||||
|
||||
lede-commit: 795e7cf60de19e7a076a46874fab7bb88b43bbff
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/uapi/linux/spi/spidev.h | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/include/uapi/linux/spi/spidev.h
|
||||
+++ b/include/uapi/linux/spi/spidev.h
|
||||
@@ -117,7 +117,7 @@ struct spi_ioc_transfer {
|
||||
|
||||
/* not all platforms use <asm-generic/ioctl.h> or _IOC_TYPECHECK() ... */
|
||||
#define SPI_MSGSIZE(N) \
|
||||
- ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << _IOC_SIZEBITS)) \
|
||||
+ ((((N)*(sizeof (struct spi_ioc_transfer))) < (1 << 13)) \
|
||||
? ((N)*(sizeof (struct spi_ioc_transfer))) : 0)
|
||||
#define SPI_IOC_MESSAGE(N) _IOW(SPI_IOC_MAGIC, 0, char[SPI_MSGSIZE(N)])
|
||||
|
||||
136
target/linux/generic/hack-5.4/220-gc_sections.patch
Normal file
136
target/linux/generic/hack-5.4/220-gc_sections.patch
Normal file
@ -0,0 +1,136 @@
|
||||
From e3d8676f5722b7622685581e06e8f53e6138e3ab Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 15 Jul 2017 23:42:36 +0200
|
||||
Subject: use -ffunction-sections, -fdata-sections and --gc-sections
|
||||
|
||||
In combination with kernel symbol export stripping this significantly reduces
|
||||
the kernel image size. Used on both ARM and MIPS architectures.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
Makefile | 10 +++----
|
||||
arch/arm/Kconfig | 1 +
|
||||
arch/arm/boot/compressed/Makefile | 1 +
|
||||
arch/arm/kernel/vmlinux.lds.S | 26 ++++++++--------
|
||||
arch/mips/Kconfig | 1 +
|
||||
arch/mips/kernel/vmlinux.lds.S | 4 +--
|
||||
include/asm-generic/vmlinux.lds.h | 63 ++++++++++++++++++++-------------------
|
||||
7 files changed, 55 insertions(+), 51 deletions(-)
|
||||
|
||||
--- a/arch/arm/Kconfig
|
||||
+++ b/arch/arm/Kconfig
|
||||
@@ -111,6 +111,7 @@ config ARM
|
||||
select HAVE_UID16
|
||||
select HAVE_VIRT_CPU_ACCOUNTING_GEN
|
||||
select IRQ_FORCED_THREADING
|
||||
+ select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
|
||||
select MODULES_USE_ELF_REL
|
||||
select NEED_DMA_MAP_STATE
|
||||
select OF_EARLY_FLATTREE if OF
|
||||
--- a/arch/arm/boot/compressed/Makefile
|
||||
+++ b/arch/arm/boot/compressed/Makefile
|
||||
@@ -106,6 +106,7 @@ ifeq ($(CONFIG_FUNCTION_TRACER),y)
|
||||
ORIG_CFLAGS := $(KBUILD_CFLAGS)
|
||||
KBUILD_CFLAGS = $(subst -pg, , $(ORIG_CFLAGS))
|
||||
endif
|
||||
+KBUILD_CFLAGS_KERNEL := $(patsubst -f%-sections,,$(KBUILD_CFLAGS_KERNEL))
|
||||
|
||||
# -fstack-protector-strong triggers protection checks in this code,
|
||||
# but it is being used too early to link to meaningful stack_chk logic.
|
||||
--- a/arch/arm/kernel/vmlinux.lds.S
|
||||
+++ b/arch/arm/kernel/vmlinux.lds.S
|
||||
@@ -100,24 +100,24 @@ SECTIONS
|
||||
}
|
||||
.init.arch.info : {
|
||||
__arch_info_begin = .;
|
||||
- *(.arch.info.init)
|
||||
+ KEEP(*(.arch.info.init))
|
||||
__arch_info_end = .;
|
||||
}
|
||||
.init.tagtable : {
|
||||
__tagtable_begin = .;
|
||||
- *(.taglist.init)
|
||||
+ KEEP(*(.taglist.init))
|
||||
__tagtable_end = .;
|
||||
}
|
||||
#ifdef CONFIG_SMP_ON_UP
|
||||
.init.smpalt : {
|
||||
__smpalt_begin = .;
|
||||
- *(.alt.smp.init)
|
||||
+ KEEP(*(.alt.smp.init))
|
||||
__smpalt_end = .;
|
||||
}
|
||||
#endif
|
||||
.init.pv_table : {
|
||||
__pv_table_begin = .;
|
||||
- *(.pv_table)
|
||||
+ KEEP(*(.pv_table))
|
||||
__pv_table_end = .;
|
||||
}
|
||||
|
||||
--- a/arch/arm/kernel/vmlinux.lds.h
|
||||
+++ b/arch/arm/kernel/vmlinux.lds.h
|
||||
@@ -22,13 +22,13 @@
|
||||
#define ARM_MMU_DISCARD(x)
|
||||
#else
|
||||
#define ARM_MMU_KEEP(x)
|
||||
-#define ARM_MMU_DISCARD(x) x
|
||||
+#define ARM_MMU_DISCARD(x) KEEP(x)
|
||||
#endif
|
||||
|
||||
#define PROC_INFO \
|
||||
. = ALIGN(4); \
|
||||
__proc_info_begin = .; \
|
||||
- *(.proc.info.init) \
|
||||
+ KEEP(*(.proc.info.init)) \
|
||||
__proc_info_end = .;
|
||||
|
||||
#define HYPERVISOR_TEXT \
|
||||
@@ -39,11 +39,11 @@
|
||||
#define IDMAP_TEXT \
|
||||
ALIGN_FUNCTION(); \
|
||||
__idmap_text_start = .; \
|
||||
- *(.idmap.text) \
|
||||
+ KEEP(*(.idmap.text)) \
|
||||
__idmap_text_end = .; \
|
||||
. = ALIGN(PAGE_SIZE); \
|
||||
__hyp_idmap_text_start = .; \
|
||||
- *(.hyp.idmap.text) \
|
||||
+ KEEP(*(.hyp.idmap.text)) \
|
||||
__hyp_idmap_text_end = .;
|
||||
|
||||
#define ARM_DISCARD \
|
||||
@@ -86,12 +86,12 @@
|
||||
. = ALIGN(8); \
|
||||
.ARM.unwind_idx : { \
|
||||
__start_unwind_idx = .; \
|
||||
- *(.ARM.exidx*) \
|
||||
+ KEEP(*(.ARM.exidx*)) \
|
||||
__stop_unwind_idx = .; \
|
||||
} \
|
||||
.ARM.unwind_tab : { \
|
||||
__start_unwind_tab = .; \
|
||||
- *(.ARM.extab*) \
|
||||
+ KEEP(*(.ARM.extab*)) \
|
||||
__stop_unwind_tab = .; \
|
||||
}
|
||||
|
||||
@@ -102,14 +102,14 @@
|
||||
#define ARM_VECTORS \
|
||||
__vectors_start = .; \
|
||||
.vectors 0xffff0000 : AT(__vectors_start) { \
|
||||
- *(.vectors) \
|
||||
+ KEEP(*(.vectors)) \
|
||||
} \
|
||||
. = __vectors_start + SIZEOF(.vectors); \
|
||||
__vectors_end = .; \
|
||||
\
|
||||
__stubs_start = .; \
|
||||
.stubs ADDR(.vectors) + 0x1000 : AT(__stubs_start) { \
|
||||
- *(.stubs) \
|
||||
+ KEEP(*(.stubs)) \
|
||||
} \
|
||||
. = __stubs_start + SIZEOF(.stubs); \
|
||||
__stubs_end = .; \
|
||||
109
target/linux/generic/hack-5.4/221-module_exports.patch
Normal file
109
target/linux/generic/hack-5.4/221-module_exports.patch
Normal file
@ -0,0 +1,109 @@
|
||||
From b14784e7883390c20ed3ff904892255404a5914b Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:05:53 +0200
|
||||
Subject: add an optional config option for stripping all unnecessary symbol exports from the kernel image
|
||||
|
||||
lede-commit: bb5a40c64b7c4f4848509fa0a6625055fc9e66cc
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/asm-generic/vmlinux.lds.h | 18 +++++++++++++++---
|
||||
include/linux/export.h | 9 ++++++++-
|
||||
scripts/Makefile.build | 2 +-
|
||||
3 files changed, 24 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/include/asm-generic/vmlinux.lds.h
|
||||
+++ b/include/asm-generic/vmlinux.lds.h
|
||||
@@ -54,6 +54,16 @@
|
||||
#define LOAD_OFFSET 0
|
||||
#endif
|
||||
|
||||
+#ifndef SYMTAB_KEEP
|
||||
+#define SYMTAB_KEEP KEEP(*(SORT(___ksymtab+*)))
|
||||
+#define SYMTAB_KEEP_GPL KEEP(*(SORT(___ksymtab_gpl+*)))
|
||||
+#endif
|
||||
+
|
||||
+#ifndef SYMTAB_DISCARD
|
||||
+#define SYMTAB_DISCARD
|
||||
+#define SYMTAB_DISCARD_GPL
|
||||
+#endif
|
||||
+
|
||||
/* Align . to a 8 byte boundary equals to maximum function alignment. */
|
||||
#define ALIGN_FUNCTION() . = ALIGN(8)
|
||||
|
||||
@@ -405,14 +415,14 @@
|
||||
/* Kernel symbol table: Normal symbols */ \
|
||||
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
||||
__start___ksymtab = .; \
|
||||
- KEEP(*(SORT(___ksymtab+*))) \
|
||||
+ SYMTAB_KEEP \
|
||||
__stop___ksymtab = .; \
|
||||
} \
|
||||
\
|
||||
/* Kernel symbol table: GPL-only symbols */ \
|
||||
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
||||
__start___ksymtab_gpl = .; \
|
||||
- KEEP(*(SORT(___ksymtab_gpl+*))) \
|
||||
+ SYMTAB_KEEP_GPL \
|
||||
__stop___ksymtab_gpl = .; \
|
||||
} \
|
||||
\
|
||||
@@ -474,7 +484,7 @@
|
||||
\
|
||||
/* Kernel symbol table: strings */ \
|
||||
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||
- *(__ksymtab_strings) \
|
||||
+ *(__ksymtab_strings+*) \
|
||||
} \
|
||||
\
|
||||
/* __*init sections */ \
|
||||
@@ -865,6 +875,8 @@
|
||||
EXIT_TEXT \
|
||||
EXIT_DATA \
|
||||
EXIT_CALL \
|
||||
+ SYMTAB_DISCARD \
|
||||
+ SYMTAB_DISCARD_GPL \
|
||||
*(.discard) \
|
||||
*(.discard.*) \
|
||||
*(.modinfo) \
|
||||
--- a/include/linux/export.h
|
||||
+++ b/include/linux/export.h
|
||||
@@ -98,18 +98,26 @@ struct kernel_symbol {
|
||||
|
||||
#else
|
||||
|
||||
+#ifdef MODULE
|
||||
+#define __EXPORT_SUFFIX(sym)
|
||||
+#else
|
||||
+#define __EXPORT_SUFFIX(sym) "+" #sym
|
||||
+#endif
|
||||
+
|
||||
#define ___export_symbol_common(sym, sec) \
|
||||
extern typeof(sym) sym; \
|
||||
__CRC_SYMBOL(sym, sec); \
|
||||
static const char __kstrtab_##sym[] \
|
||||
- __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
|
||||
+ __attribute__((section("__ksymtab_strings" \
|
||||
+ __EXPORT_SUFFIX(sym)), used, aligned(1))) \
|
||||
= #sym \
|
||||
|
||||
/* For every exported symbol, place a struct in the __ksymtab section */
|
||||
#define ___EXPORT_SYMBOL_NS(sym, sec, ns) \
|
||||
___export_symbol_common(sym, sec); \
|
||||
static const char __kstrtabns_##sym[] \
|
||||
- __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
|
||||
+ __attribute__((section("__ksymtab_strings" \
|
||||
+ __EXPORT_SUFFIX(sym)), used, aligned(1))) \
|
||||
= #ns; \
|
||||
__KSYMTAB_ENTRY_NS(sym, sec)
|
||||
|
||||
--- a/scripts/Makefile.build
|
||||
+++ b/scripts/Makefile.build
|
||||
@@ -353,7 +353,7 @@ targets += $(extra-y) $(MAKECMDGOALS) $(
|
||||
# Linker scripts preprocessor (.lds.S -> .lds)
|
||||
# ---------------------------------------------------------------------------
|
||||
quiet_cmd_cpp_lds_S = LDS $@
|
||||
- cmd_cpp_lds_S = $(CPP) $(cpp_flags) -P -U$(ARCH) \
|
||||
+ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -U$(ARCH) \
|
||||
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
|
||||
|
||||
$(obj)/%.lds: $(src)/%.lds.S FORCE
|
||||
71
target/linux/generic/hack-5.4/230-openwrt_lzma_options.patch
Normal file
71
target/linux/generic/hack-5.4/230-openwrt_lzma_options.patch
Normal file
@ -0,0 +1,71 @@
|
||||
From b3d00b452467f621317953d9e4c6f9ae8dcfd271 Mon Sep 17 00:00:00 2001
|
||||
From: Imre Kaloz <kaloz@openwrt.org>
|
||||
Date: Fri, 7 Jul 2017 17:06:55 +0200
|
||||
Subject: use the openwrt lzma options for now
|
||||
|
||||
lede-commit: 548de949f392049420a6a1feeef118b30ab8ea8c
|
||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||
---
|
||||
lib/decompress.c | 1 +
|
||||
scripts/Makefile.lib | 2 +-
|
||||
usr/gen_initramfs_list.sh | 10 +++++-----
|
||||
3 files changed, 7 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/lib/decompress.c
|
||||
+++ b/lib/decompress.c
|
||||
@@ -49,6 +49,7 @@ static const struct compress_format comp
|
||||
{ {0x1f, 0x9e}, "gzip", gunzip },
|
||||
{ {0x42, 0x5a}, "bzip2", bunzip2 },
|
||||
{ {0x5d, 0x00}, "lzma", unlzma },
|
||||
+ { {0x6d, 0x00}, "lzma-openwrt", unlzma },
|
||||
{ {0xfd, 0x37}, "xz", unxz },
|
||||
{ {0x89, 0x4c}, "lzo", unlzo },
|
||||
{ {0x02, 0x21}, "lz4", unlz4 },
|
||||
--- a/scripts/Makefile.lib
|
||||
+++ b/scripts/Makefile.lib
|
||||
@@ -328,7 +328,7 @@ quiet_cmd_bzip2 = BZIP2 $@
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
quiet_cmd_lzma = LZMA $@
|
||||
- cmd_lzma = { cat $(real-prereqs) | lzma -9; $(size_append); } > $@
|
||||
+ cmd_lzma = { cat $(real-prereqs) | lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so; $(size_append); } > $@
|
||||
|
||||
quiet_cmd_lzo = LZO $@
|
||||
cmd_lzo = { cat $(real-prereqs) | lzop -9; $(size_append); } > $@
|
||||
--- a/usr/gen_initramfs_list.sh
|
||||
+++ b/usr/gen_initramfs_list.sh
|
||||
@@ -229,7 +229,7 @@ cpio_list=
|
||||
output="/dev/stdout"
|
||||
output_file=""
|
||||
is_cpio_compressed=
|
||||
-compr="gzip -n -9 -f"
|
||||
+compr="gzip -n -9 -f -"
|
||||
|
||||
arg="$1"
|
||||
case "$arg" in
|
||||
@@ -245,13 +245,13 @@ case "$arg" in
|
||||
output=${cpio_list}
|
||||
echo "$output_file" | grep -q "\.gz$" \
|
||||
&& [ -x "`which gzip 2> /dev/null`" ] \
|
||||
- && compr="gzip -n -9 -f"
|
||||
+ && compr="gzip -n -9 -f -"
|
||||
echo "$output_file" | grep -q "\.bz2$" \
|
||||
&& [ -x "`which bzip2 2> /dev/null`" ] \
|
||||
- && compr="bzip2 -9 -f"
|
||||
+ && compr="bzip2 -9 -f -"
|
||||
echo "$output_file" | grep -q "\.lzma$" \
|
||||
&& [ -x "`which lzma 2> /dev/null`" ] \
|
||||
- && compr="lzma -9 -f"
|
||||
+ && compr="lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so"
|
||||
echo "$output_file" | grep -q "\.xz$" \
|
||||
&& [ -x "`which xz 2> /dev/null`" ] \
|
||||
&& compr="xz --check=crc32 --lzma2=dict=1MiB"
|
||||
@@ -320,7 +320,7 @@ if [ ! -z ${output_file} ]; then
|
||||
if [ "${is_cpio_compressed}" = "compressed" ]; then
|
||||
cat ${cpio_tfile} > ${output_file}
|
||||
else
|
||||
- (cat ${cpio_tfile} | ${compr} - > ${output_file}) \
|
||||
+ (cat ${cpio_tfile} | ${compr} > ${output_file}) \
|
||||
|| (rm -f ${output_file} ; false)
|
||||
fi
|
||||
[ -z ${cpio_file} ] && rm ${cpio_tfile}
|
||||
27
target/linux/generic/hack-5.4/250-netfilter_depends.patch
Normal file
27
target/linux/generic/hack-5.4/250-netfilter_depends.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: hack: net: remove bogus netfilter dependencies
|
||||
|
||||
lede-commit: 589d2a377dee27d206fc3725325309cf649e4df6
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/netfilter/Kconfig | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -240,7 +240,6 @@ config NF_CONNTRACK_FTP
|
||||
|
||||
config NF_CONNTRACK_H323
|
||||
tristate "H.323 protocol support"
|
||||
- depends on IPV6 || IPV6=n
|
||||
depends on NETFILTER_ADVANCED
|
||||
help
|
||||
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
|
||||
@@ -1100,7 +1099,6 @@ config NETFILTER_XT_TARGET_SECMARK
|
||||
|
||||
config NETFILTER_XT_TARGET_TCPMSS
|
||||
tristate '"TCPMSS" target support'
|
||||
- depends on IPV6 || IPV6=n
|
||||
default m if NETFILTER_ADVANCED=n
|
||||
---help---
|
||||
This option adds a `TCPMSS' target, which allows you to alter the
|
||||
198
target/linux/generic/hack-5.4/251-sound_kconfig.patch
Normal file
198
target/linux/generic/hack-5.4/251-sound_kconfig.patch
Normal file
@ -0,0 +1,198 @@
|
||||
From da3c50704f14132f4adf80d48e9a4cd5d46e54c9 Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Fri, 7 Jul 2017 17:09:21 +0200
|
||||
Subject: kconfig: owrt specifc dependencies
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
crypto/Kconfig | 10 +++++-----
|
||||
drivers/bcma/Kconfig | 1 +
|
||||
drivers/ssb/Kconfig | 3 ++-
|
||||
lib/Kconfig | 8 ++++----
|
||||
net/netfilter/Kconfig | 2 +-
|
||||
net/wireless/Kconfig | 17 ++++++++++-------
|
||||
sound/core/Kconfig | 4 ++--
|
||||
7 files changed, 25 insertions(+), 20 deletions(-)
|
||||
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -33,7 +33,7 @@ config CRYPTO_FIPS
|
||||
this is.
|
||||
|
||||
config CRYPTO_ALGAPI
|
||||
- tristate
|
||||
+ tristate "ALGAPI"
|
||||
select CRYPTO_ALGAPI2
|
||||
help
|
||||
This option provides the API for cryptographic algorithms.
|
||||
@@ -42,7 +42,7 @@ config CRYPTO_ALGAPI2
|
||||
tristate
|
||||
|
||||
config CRYPTO_AEAD
|
||||
- tristate
|
||||
+ tristate "AEAD"
|
||||
select CRYPTO_AEAD2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -53,7 +53,7 @@ config CRYPTO_AEAD2
|
||||
select CRYPTO_RNG2
|
||||
|
||||
config CRYPTO_BLKCIPHER
|
||||
- tristate
|
||||
+ tristate "BLKCIPHER"
|
||||
select CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_RNG2
|
||||
|
||||
config CRYPTO_HASH
|
||||
- tristate
|
||||
+ tristate "HASH"
|
||||
select CRYPTO_HASH2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -72,7 +72,7 @@ config CRYPTO_HASH2
|
||||
select CRYPTO_ALGAPI2
|
||||
|
||||
config CRYPTO_RNG
|
||||
- tristate
|
||||
+ tristate "RNG"
|
||||
select CRYPTO_RNG2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
--- a/drivers/bcma/Kconfig
|
||||
+++ b/drivers/bcma/Kconfig
|
||||
@@ -16,6 +16,7 @@ if BCMA
|
||||
# Support for Block-I/O. SELECT this from the driver that needs it.
|
||||
config BCMA_BLOCKIO
|
||||
bool
|
||||
+ default y
|
||||
|
||||
config BCMA_HOST_PCI_POSSIBLE
|
||||
bool
|
||||
--- a/drivers/ssb/Kconfig
|
||||
+++ b/drivers/ssb/Kconfig
|
||||
@@ -29,6 +29,7 @@ config SSB_SPROM
|
||||
config SSB_BLOCKIO
|
||||
bool
|
||||
depends on SSB
|
||||
+ default y
|
||||
|
||||
config SSB_PCIHOST_POSSIBLE
|
||||
bool
|
||||
@@ -49,7 +50,7 @@ config SSB_PCIHOST
|
||||
config SSB_B43_PCI_BRIDGE
|
||||
bool
|
||||
depends on SSB_PCIHOST
|
||||
- default n
|
||||
+ default y
|
||||
|
||||
config SSB_PCMCIAHOST_POSSIBLE
|
||||
bool
|
||||
--- a/lib/Kconfig
|
||||
+++ b/lib/Kconfig
|
||||
@@ -402,16 +402,16 @@ config BCH_CONST_T
|
||||
# Textsearch support is select'ed if needed
|
||||
#
|
||||
config TEXTSEARCH
|
||||
- bool
|
||||
+ bool "Textsearch support"
|
||||
|
||||
config TEXTSEARCH_KMP
|
||||
- tristate
|
||||
+ tristate "Textsearch KMP"
|
||||
|
||||
config TEXTSEARCH_BM
|
||||
- tristate
|
||||
+ tristate "Textsearch BM"
|
||||
|
||||
config TEXTSEARCH_FSM
|
||||
- tristate
|
||||
+ tristate "Textsearch FSM"
|
||||
|
||||
config BTREE
|
||||
bool
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -11,7 +11,7 @@ config NETFILTER_INGRESS
|
||||
infrastructure.
|
||||
|
||||
config NETFILTER_NETLINK
|
||||
- tristate
|
||||
+ tristate "Netfilter NFNETLINK interface"
|
||||
|
||||
config NETFILTER_FAMILY_BRIDGE
|
||||
bool
|
||||
--- a/net/wireless/Kconfig
|
||||
+++ b/net/wireless/Kconfig
|
||||
@@ -1,6 +1,6 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
config WIRELESS_EXT
|
||||
- bool
|
||||
+ bool "Wireless extensions"
|
||||
|
||||
config WEXT_CORE
|
||||
def_bool y
|
||||
@@ -12,10 +12,10 @@ config WEXT_PROC
|
||||
depends on WEXT_CORE
|
||||
|
||||
config WEXT_SPY
|
||||
- bool
|
||||
+ bool "WEXT_SPY"
|
||||
|
||||
config WEXT_PRIV
|
||||
- bool
|
||||
+ bool "WEXT_PRIV"
|
||||
|
||||
config CFG80211
|
||||
tristate "cfg80211 - wireless configuration API"
|
||||
@@ -203,7 +203,7 @@ config CFG80211_WEXT_EXPORT
|
||||
endif # CFG80211
|
||||
|
||||
config LIB80211
|
||||
- tristate
|
||||
+ tristate "LIB80211"
|
||||
default n
|
||||
help
|
||||
This options enables a library of common routines used
|
||||
@@ -212,16 +212,16 @@ config LIB80211
|
||||
Drivers should select this themselves if needed.
|
||||
|
||||
config LIB80211_CRYPT_WEP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_WEP"
|
||||
select CRYPTO_LIB_ARC4
|
||||
|
||||
config LIB80211_CRYPT_CCMP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_CCMP"
|
||||
select CRYPTO_AES
|
||||
select CRYPTO_CCM
|
||||
|
||||
config LIB80211_CRYPT_TKIP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_TKIP"
|
||||
select CRYPTO_LIB_ARC4
|
||||
|
||||
config LIB80211_DEBUG
|
||||
--- a/sound/core/Kconfig
|
||||
+++ b/sound/core/Kconfig
|
||||
@@ -17,7 +17,7 @@ config SND_DMAENGINE_PCM
|
||||
tristate
|
||||
|
||||
config SND_HWDEP
|
||||
- tristate
|
||||
+ tristate "Sound hardware support"
|
||||
|
||||
config SND_SEQ_DEVICE
|
||||
tristate
|
||||
@@ -27,7 +27,7 @@ config SND_RAWMIDI
|
||||
select SND_SEQ_DEVICE if SND_SEQUENCER != n
|
||||
|
||||
config SND_COMPRESS_OFFLOAD
|
||||
- tristate
|
||||
+ tristate "Compression offloading support"
|
||||
|
||||
config SND_JACK
|
||||
bool
|
||||
125
target/linux/generic/hack-5.4/259-regmap_dynamic.patch
Normal file
125
target/linux/generic/hack-5.4/259-regmap_dynamic.patch
Normal file
@ -0,0 +1,125 @@
|
||||
From 811d9e2268a62b830cfe93cd8bc929afcb8b198b Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 15 Jul 2017 21:12:38 +0200
|
||||
Subject: kernel: move regmap bloat out of the kernel image if it is only being used in modules
|
||||
|
||||
lede-commit: 96f39119815028073583e4fca3a9c5fe9141e998
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/base/regmap/Kconfig | 15 ++++++++++-----
|
||||
drivers/base/regmap/Makefile | 12 ++++++++----
|
||||
drivers/base/regmap/regmap.c | 3 +++
|
||||
include/linux/regmap.h | 2 +-
|
||||
4 files changed, 22 insertions(+), 10 deletions(-)
|
||||
|
||||
--- a/drivers/base/regmap/Kconfig
|
||||
+++ b/drivers/base/regmap/Kconfig
|
||||
@@ -4,9 +4,8 @@
|
||||
# subsystems should select the appropriate symbols.
|
||||
|
||||
config REGMAP
|
||||
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_W1 || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_SCCB || REGMAP_I3C)
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
- bool
|
||||
+ tristate
|
||||
|
||||
config REGCACHE_COMPRESSED
|
||||
select LZO_COMPRESS
|
||||
@@ -18,38 +17,49 @@ config REGMAP_AC97
|
||||
|
||||
config REGMAP_I2C
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on I2C
|
||||
|
||||
config REGMAP_SLIMBUS
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on SLIMBUS
|
||||
|
||||
config REGMAP_SPI
|
||||
tristate
|
||||
+ select REGMAP
|
||||
+ depends on SPI_MASTER
|
||||
depends on SPI
|
||||
|
||||
config REGMAP_SPMI
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on SPMI
|
||||
|
||||
config REGMAP_W1
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on W1
|
||||
|
||||
config REGMAP_MMIO
|
||||
tristate
|
||||
+ select REGMAP
|
||||
|
||||
config REGMAP_IRQ
|
||||
bool
|
||||
+ select REGMAP
|
||||
|
||||
config REGMAP_SOUNDWIRE
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on SOUNDWIRE
|
||||
|
||||
config REGMAP_SCCB
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on I2C
|
||||
|
||||
config REGMAP_I3C
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on I3C
|
||||
--- a/drivers/base/regmap/Makefile
|
||||
+++ b/drivers/base/regmap/Makefile
|
||||
@@ -2,10 +2,14 @@
|
||||
# For include/trace/define_trace.h to include trace.h
|
||||
CFLAGS_regmap.o := -I$(src)
|
||||
|
||||
-obj-$(CONFIG_REGMAP) += regmap.o regcache.o
|
||||
-obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-flat.o
|
||||
-obj-$(CONFIG_REGCACHE_COMPRESSED) += regcache-lzo.o
|
||||
-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
|
||||
+regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-flat.o
|
||||
+ifdef CONFIG_DEBUG_FS
|
||||
+regmap-core-objs += regmap-debugfs.o
|
||||
+endif
|
||||
+ifdef CONFIG_REGCACHE_COMPRESSED
|
||||
+regmap-core-objs += regcache-lzo.o
|
||||
+endif
|
||||
+obj-$(CONFIG_REGMAP) += regmap-core.o
|
||||
obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
|
||||
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
|
||||
obj-$(CONFIG_REGMAP_SLIMBUS) += regmap-slimbus.o
|
||||
--- a/drivers/base/regmap/regmap.c
|
||||
+++ b/drivers/base/regmap/regmap.c
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
@@ -3124,3 +3125,5 @@ static int __init regmap_initcall(void)
|
||||
return 0;
|
||||
}
|
||||
postcore_initcall(regmap_initcall);
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/include/linux/regmap.h
|
||||
+++ b/include/linux/regmap.h
|
||||
@@ -185,7 +185,7 @@ struct reg_sequence {
|
||||
pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
|
||||
})
|
||||
|
||||
-#ifdef CONFIG_REGMAP
|
||||
+#if IS_REACHABLE(CONFIG_REGMAP)
|
||||
|
||||
enum regmap_endian {
|
||||
/* Unspecified -> 0 -> Backwards compatible default */
|
||||
@ -0,0 +1,70 @@
|
||||
From fd1799b0bf5efa46dd3e6dfbbf3955564807e508 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:12:51 +0200
|
||||
Subject: kernel: prevent cryptomgr from pulling in useless extra dependencies for tests that are not run
|
||||
|
||||
Reduces kernel size after LZMA by about 5k on MIPS
|
||||
|
||||
lede-commit: 044c316167e076479a344c59905e5b435b84a77f
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
crypto/Kconfig | 13 ++++++-------
|
||||
crypto/algboss.c | 4 ++++
|
||||
2 files changed, 10 insertions(+), 7 deletions(-)
|
||||
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -120,13 +120,13 @@ config CRYPTO_MANAGER
|
||||
cbc(aes).
|
||||
|
||||
config CRYPTO_MANAGER2
|
||||
- def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y)
|
||||
- select CRYPTO_AEAD2
|
||||
- select CRYPTO_HASH2
|
||||
- select CRYPTO_BLKCIPHER2
|
||||
- select CRYPTO_AKCIPHER2
|
||||
- select CRYPTO_KPP2
|
||||
- select CRYPTO_ACOMP2
|
||||
+ def_tristate CRYPTO_MANAGER || (CRYPTO_MANAGER!=n && CRYPTO_ALGAPI=y && !CRYPTO_MANAGER_DISABLE_TESTS)
|
||||
+ select CRYPTO_AEAD2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ select CRYPTO_HASH2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ select CRYPTO_BLKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ select CRYPTO_AKCIPHER2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ select CRYPTO_KPP2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ select CRYPTO_ACOMP2 if !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
|
||||
config CRYPTO_USER
|
||||
tristate "Userspace cryptographic algorithm configuration"
|
||||
@@ -136,8 +136,6 @@ config CRYPTO_USER
|
||||
Userspace configuration for cryptographic instantiations such as
|
||||
cbc(aes).
|
||||
|
||||
-if CRYPTO_MANAGER2
|
||||
-
|
||||
config CRYPTO_MANAGER_DISABLE_TESTS
|
||||
bool "Disable run-time self tests"
|
||||
default y
|
||||
@@ -145,6 +143,8 @@ config CRYPTO_MANAGER_DISABLE_TESTS
|
||||
Disable run-time self tests that normally take place at
|
||||
algorithm registration.
|
||||
|
||||
+if CRYPTO_MANAGER2
|
||||
+
|
||||
config CRYPTO_MANAGER_EXTRA_TESTS
|
||||
bool "Enable extra run-time crypto self tests"
|
||||
depends on DEBUG_KERNEL && !CRYPTO_MANAGER_DISABLE_TESTS
|
||||
--- a/crypto/algboss.c
|
||||
+++ b/crypto/algboss.c
|
||||
@@ -242,8 +242,12 @@ static int cryptomgr_schedule_test(struc
|
||||
type = alg->cra_flags;
|
||||
|
||||
/* Do not test internal algorithms. */
|
||||
+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
|
||||
+ type |= CRYPTO_ALG_TESTED;
|
||||
+#else
|
||||
if (type & CRYPTO_ALG_INTERNAL)
|
||||
type |= CRYPTO_ALG_TESTED;
|
||||
+#endif
|
||||
|
||||
param->type = type;
|
||||
|
||||
15
target/linux/generic/hack-5.4/260-lib-arc4-unhide.patch
Normal file
15
target/linux/generic/hack-5.4/260-lib-arc4-unhide.patch
Normal file
@ -0,0 +1,15 @@
|
||||
This makes it possible to select CONFIG_CRYPTO_LIB_ARC4 directly. We
|
||||
need this to be able to compile this into the kernel and make use of it
|
||||
from backports.
|
||||
|
||||
--- a/crypto/Kconfig
|
||||
+++ b/crypto/Kconfig
|
||||
@@ -1151,7 +1151,7 @@ config CRYPTO_ANUBIS
|
||||
<http://www.larc.usp.br/~pbarreto/AnubisPage.html>
|
||||
|
||||
config CRYPTO_LIB_ARC4
|
||||
- tristate
|
||||
+ tristate "ARC4 cipher library"
|
||||
|
||||
config CRYPTO_ARC4
|
||||
tristate "ARC4 cipher algorithm"
|
||||
84
target/linux/generic/hack-5.4/280-rfkill-stubs.patch
Normal file
84
target/linux/generic/hack-5.4/280-rfkill-stubs.patch
Normal file
@ -0,0 +1,84 @@
|
||||
From 236c1acdfef5958010ac9814a9872e0a46fd78ee Mon Sep 17 00:00:00 2001
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Date: Fri, 7 Jul 2017 17:13:44 +0200
|
||||
Subject: rfkill: add fake rfkill support
|
||||
|
||||
allow building of modules depending on RFKILL even if RFKILL is not enabled.
|
||||
|
||||
Signed-off-by: John Crispin <john@phrozen.org>
|
||||
---
|
||||
include/linux/rfkill.h | 2 +-
|
||||
net/Makefile | 2 +-
|
||||
net/rfkill/Kconfig | 14 +++++++++-----
|
||||
net/rfkill/Makefile | 2 +-
|
||||
4 files changed, 12 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/include/linux/rfkill.h
|
||||
+++ b/include/linux/rfkill.h
|
||||
@@ -64,7 +64,7 @@ struct rfkill_ops {
|
||||
int (*set_block)(void *data, bool blocked);
|
||||
};
|
||||
|
||||
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
|
||||
+#if defined(CONFIG_RFKILL_FULL) || defined(CONFIG_RFKILL_FULL_MODULE)
|
||||
/**
|
||||
* rfkill_alloc - Allocate rfkill structure
|
||||
* @name: name of the struct -- the string is not copied internally
|
||||
--- a/net/Makefile
|
||||
+++ b/net/Makefile
|
||||
@@ -53,7 +53,7 @@ obj-$(CONFIG_TIPC) += tipc/
|
||||
obj-$(CONFIG_NETLABEL) += netlabel/
|
||||
obj-$(CONFIG_IUCV) += iucv/
|
||||
obj-$(CONFIG_SMC) += smc/
|
||||
-obj-$(CONFIG_RFKILL) += rfkill/
|
||||
+obj-$(CONFIG_RFKILL_FULL) += rfkill/
|
||||
obj-$(CONFIG_NET_9P) += 9p/
|
||||
obj-$(CONFIG_CAIF) += caif/
|
||||
ifneq ($(CONFIG_DCB),)
|
||||
--- a/net/rfkill/Kconfig
|
||||
+++ b/net/rfkill/Kconfig
|
||||
@@ -2,7 +2,11 @@
|
||||
#
|
||||
# RF switch subsystem configuration
|
||||
#
|
||||
-menuconfig RFKILL
|
||||
+config RFKILL
|
||||
+ bool
|
||||
+ default y
|
||||
+
|
||||
+menuconfig RFKILL_FULL
|
||||
tristate "RF switch subsystem support"
|
||||
help
|
||||
Say Y here if you want to have control over RF switches
|
||||
@@ -14,19 +18,19 @@ menuconfig RFKILL
|
||||
# LED trigger support
|
||||
config RFKILL_LEDS
|
||||
bool
|
||||
- depends on RFKILL
|
||||
+ depends on RFKILL_FULL
|
||||
depends on LEDS_TRIGGERS = y || RFKILL = LEDS_TRIGGERS
|
||||
default y
|
||||
|
||||
config RFKILL_INPUT
|
||||
bool "RF switch input support" if EXPERT
|
||||
- depends on RFKILL
|
||||
+ depends on RFKILL_FULL
|
||||
depends on INPUT = y || RFKILL = INPUT
|
||||
default y if !EXPERT
|
||||
|
||||
config RFKILL_GPIO
|
||||
tristate "GPIO RFKILL driver"
|
||||
- depends on RFKILL
|
||||
+ depends on RFKILL_FULL
|
||||
depends on GPIOLIB || COMPILE_TEST
|
||||
default n
|
||||
help
|
||||
--- a/net/rfkill/Makefile
|
||||
+++ b/net/rfkill/Makefile
|
||||
@@ -5,5 +5,5 @@
|
||||
|
||||
rfkill-y += core.o
|
||||
rfkill-$(CONFIG_RFKILL_INPUT) += input.o
|
||||
-obj-$(CONFIG_RFKILL) += rfkill.o
|
||||
+obj-$(CONFIG_RFKILL_FULL) += rfkill.o
|
||||
obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o
|
||||
@ -0,0 +1,64 @@
|
||||
From: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
|
||||
Date: Fri, 7 Jun 2013 18:35:22 -0500
|
||||
Subject: MIPS: r4k_cache: use more efficient cache blast
|
||||
|
||||
Optimize the compiler output for larger cache blast cases that are
|
||||
common for DMA-based networking.
|
||||
|
||||
Signed-off-by: Ben Menchaca <ben.menchaca@qca.qualcomm.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
--- a/arch/mips/include/asm/r4kcache.h
|
||||
+++ b/arch/mips/include/asm/r4kcache.h
|
||||
@@ -617,14 +617,46 @@ static inline void prot##extra##blast_##
|
||||
unsigned long end) \
|
||||
{ \
|
||||
unsigned long lsize = cpu_##desc##_line_size(); \
|
||||
+ unsigned long lsize_2 = lsize * 2; \
|
||||
+ unsigned long lsize_3 = lsize * 3; \
|
||||
+ unsigned long lsize_4 = lsize * 4; \
|
||||
+ unsigned long lsize_5 = lsize * 5; \
|
||||
+ unsigned long lsize_6 = lsize * 6; \
|
||||
+ unsigned long lsize_7 = lsize * 7; \
|
||||
+ unsigned long lsize_8 = lsize * 8; \
|
||||
unsigned long addr = start & ~(lsize - 1); \
|
||||
- unsigned long aend = (end - 1) & ~(lsize - 1); \
|
||||
+ unsigned long aend = (end + lsize - 1) & ~(lsize - 1); \
|
||||
+ int lines = (aend - addr) / lsize; \
|
||||
\
|
||||
- while (1) { \
|
||||
+ while (lines >= 8) { \
|
||||
+ prot##cache_op(hitop, addr); \
|
||||
+ prot##cache_op(hitop, addr + lsize); \
|
||||
+ prot##cache_op(hitop, addr + lsize_2); \
|
||||
+ prot##cache_op(hitop, addr + lsize_3); \
|
||||
+ prot##cache_op(hitop, addr + lsize_4); \
|
||||
+ prot##cache_op(hitop, addr + lsize_5); \
|
||||
+ prot##cache_op(hitop, addr + lsize_6); \
|
||||
+ prot##cache_op(hitop, addr + lsize_7); \
|
||||
+ addr += lsize_8; \
|
||||
+ lines -= 8; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (lines & 0x4) { \
|
||||
+ prot##cache_op(hitop, addr); \
|
||||
+ prot##cache_op(hitop, addr + lsize); \
|
||||
+ prot##cache_op(hitop, addr + lsize_2); \
|
||||
+ prot##cache_op(hitop, addr + lsize_3); \
|
||||
+ addr += lsize_4; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (lines & 0x2) { \
|
||||
+ prot##cache_op(hitop, addr); \
|
||||
+ prot##cache_op(hitop, addr + lsize); \
|
||||
+ addr += lsize_2; \
|
||||
+ } \
|
||||
+ \
|
||||
+ if (lines & 0x1) { \
|
||||
prot##cache_op(hitop, addr); \
|
||||
- if (addr == aend) \
|
||||
- break; \
|
||||
- addr += lsize; \
|
||||
} \
|
||||
}
|
||||
|
||||
@ -0,0 +1,38 @@
|
||||
From: John Crispin <john@phrozen.org>
|
||||
Subject: hack: kernel: add generic image_cmdline hack to MIPS targets
|
||||
|
||||
lede-commit: d59f5b3a987a48508257a0ddbaeadc7909f9f976
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
arch/mips/Kconfig | 4 ++++
|
||||
arch/mips/kernel/head.S | 6 ++++++
|
||||
2 files changed, 10 insertions(+)
|
||||
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -1156,6 +1156,10 @@ config SYNC_R4K
|
||||
config MIPS_MACHINE
|
||||
def_bool n
|
||||
|
||||
+config IMAGE_CMDLINE_HACK
|
||||
+ bool "OpenWrt specific image command line hack"
|
||||
+ default n
|
||||
+
|
||||
config NO_IOPORT_MAP
|
||||
def_bool n
|
||||
|
||||
--- a/arch/mips/kernel/head.S
|
||||
+++ b/arch/mips/kernel/head.S
|
||||
@@ -79,6 +79,12 @@ FEXPORT(__kernel_entry)
|
||||
j kernel_entry
|
||||
#endif /* CONFIG_BOOT_RAW */
|
||||
|
||||
+#ifdef CONFIG_IMAGE_CMDLINE_HACK
|
||||
+ .ascii "CMDLINE:"
|
||||
+EXPORT(__image_cmdline)
|
||||
+ .fill 0x400
|
||||
+#endif /* CONFIG_IMAGE_CMDLINE_HACK */
|
||||
+
|
||||
__REF
|
||||
|
||||
NESTED(kernel_entry, 16, sp) # kernel entry point
|
||||
@ -0,0 +1,39 @@
|
||||
From 107c0964cb8db7ca28ac5199426414fdab3c274d Mon Sep 17 00:00:00 2001
|
||||
From: "Alexandros C. Couloumbis" <alex@ozo.com>
|
||||
Date: Fri, 7 Jul 2017 17:14:51 +0200
|
||||
Subject: hack: arch: powerpc: drop register save/restore library from modules
|
||||
|
||||
Upstream GCC uses a libgcc function for saving/restoring registers. This
|
||||
makes the code bigger, and upstream kernels need to carry that function
|
||||
for every single kernel module. Our GCC is patched to avoid those
|
||||
references, so we can drop the extra bloat for modules.
|
||||
|
||||
lede-commit: e8e1084654f50904e6bf77b70b2de3f137d7b3ec
|
||||
Signed-off-by: Alexandros C. Couloumbis <alex@ozo.com>
|
||||
---
|
||||
arch/powerpc/Makefile | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
--- a/arch/powerpc/Makefile
|
||||
+++ b/arch/powerpc/Makefile
|
||||
@@ -61,20 +61,6 @@ machine-$(CONFIG_PPC64) += 64
|
||||
machine-$(CONFIG_CPU_LITTLE_ENDIAN) += le
|
||||
UTS_MACHINE := $(subst $(space),,$(machine-y))
|
||||
|
||||
-# XXX This needs to be before we override LD below
|
||||
-ifdef CONFIG_PPC32
|
||||
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
|
||||
-else
|
||||
-KBUILD_LDS_MODULE += $(srctree)/arch/powerpc/kernel/module.lds
|
||||
-ifeq ($(call ld-ifversion, -ge, 225000000, y),y)
|
||||
-# Have the linker provide sfpr if possible.
|
||||
-# There is a corresponding test in arch/powerpc/lib/Makefile
|
||||
-KBUILD_LDFLAGS_MODULE += --save-restore-funcs
|
||||
-else
|
||||
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
|
||||
-endif
|
||||
-endif
|
||||
-
|
||||
ifdef CONFIG_CPU_LITTLE_ENDIAN
|
||||
KBUILD_CFLAGS += -mlittle-endian
|
||||
KBUILD_LDFLAGS += -EL
|
||||
1040
target/linux/generic/hack-5.4/531-debloat_lzma.patch
Normal file
1040
target/linux/generic/hack-5.4/531-debloat_lzma.patch
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,41 @@
|
||||
From 2e864386e62e702a343be2507062ee08d5dfc810 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Green <evgreen@chromium.org>
|
||||
Date: Thu, 14 Nov 2019 15:50:07 -0800
|
||||
Subject: loop: Report EOPNOTSUPP properly
|
||||
|
||||
Properly plumb out EOPNOTSUPP from loop driver operations, which may
|
||||
get returned when for instance a discard operation is attempted but not
|
||||
supported by the underlying block device. Before this change, everything
|
||||
was reported in the log as an I/O error, which is scary and not
|
||||
helpful in debugging.
|
||||
|
||||
Signed-off-by: Evan Green <evgreen@chromium.org>
|
||||
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
|
||||
Reviewed-by: Bart Van Assche <bvanassche@acm.org>
|
||||
---
|
||||
drivers/block/loop.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/block/loop.c
|
||||
+++ b/drivers/block/loop.c
|
||||
@@ -461,7 +461,7 @@ static void lo_complete_rq(struct reques
|
||||
if (!cmd->use_aio || cmd->ret < 0 || cmd->ret == blk_rq_bytes(rq) ||
|
||||
req_op(rq) != REQ_OP_READ) {
|
||||
if (cmd->ret < 0)
|
||||
- ret = BLK_STS_IOERR;
|
||||
+ ret = errno_to_blk_status(cmd->ret);
|
||||
goto end_io;
|
||||
}
|
||||
|
||||
@@ -1950,7 +1950,10 @@ static void loop_handle_cmd(struct loop_
|
||||
failed:
|
||||
/* complete non-aio request */
|
||||
if (!cmd->use_aio || ret) {
|
||||
- cmd->ret = ret ? -EIO : 0;
|
||||
+ if (ret == -EOPNOTSUPP)
|
||||
+ cmd->ret = ret;
|
||||
+ else
|
||||
+ cmd->ret = ret ? -EIO : 0;
|
||||
blk_mq_complete_request(rq);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,101 @@
|
||||
From 3117c3f45edbcc269baaebd3d13f39b7bf884aa6 Mon Sep 17 00:00:00 2001
|
||||
From: Evan Green <evgreen@chromium.org>
|
||||
Date: Thu, 14 Nov 2019 15:50:08 -0800
|
||||
Subject: loop: Better discard support for block devices
|
||||
|
||||
If the backing device for a loop device is itself a block device,
|
||||
then mirror the "write zeroes" capabilities of the underlying
|
||||
block device into the loop device. Copy this capability into both
|
||||
max_write_zeroes_sectors and max_discard_sectors of the loop device.
|
||||
|
||||
The reason for this is that REQ_OP_DISCARD on a loop device translates
|
||||
into blkdev_issue_zeroout(), rather than blkdev_issue_discard(). This
|
||||
presents a consistent interface for loop devices (that discarded data
|
||||
is zeroed), regardless of the backing device type of the loop device.
|
||||
There should be no behavior change for loop devices backed by regular
|
||||
files.
|
||||
|
||||
This change fixes blktest block/003, and removes an extraneous
|
||||
error print in block/013 when testing on a loop device backed
|
||||
by a block device that does not support discard.
|
||||
|
||||
Signed-off-by: Evan Green <evgreen@chromium.org>
|
||||
Reviewed-by: Gwendal Grignou <gwendal@chromium.org>
|
||||
Reviewed-by: Chaitanya Kulkarni <chaitanya.kulkarni@wdc.com>
|
||||
---
|
||||
drivers/block/loop.c | 40 +++++++++++++++++++++++++++++-----------
|
||||
1 file changed, 29 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/block/loop.c
|
||||
+++ b/drivers/block/loop.c
|
||||
@@ -427,11 +427,12 @@ static int lo_fallocate(struct loop_devi
|
||||
* information.
|
||||
*/
|
||||
struct file *file = lo->lo_backing_file;
|
||||
+ struct request_queue *q = lo->lo_queue;
|
||||
int ret;
|
||||
|
||||
mode |= FALLOC_FL_KEEP_SIZE;
|
||||
|
||||
- if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
|
||||
+ if (!blk_queue_discard(q)) {
|
||||
ret = -EOPNOTSUPP;
|
||||
goto out;
|
||||
}
|
||||
@@ -862,6 +863,21 @@ static void loop_config_discard(struct l
|
||||
struct file *file = lo->lo_backing_file;
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
struct request_queue *q = lo->lo_queue;
|
||||
+ struct request_queue *backingq;
|
||||
+
|
||||
+ /*
|
||||
+ * If the backing device is a block device, mirror its zeroing
|
||||
+ * capability. REQ_OP_DISCARD translates to a zero-out even when backed
|
||||
+ * by block devices to keep consistent behavior with file-backed loop
|
||||
+ * devices.
|
||||
+ */
|
||||
+ if (S_ISBLK(inode->i_mode) && !lo->lo_encrypt_key_size) {
|
||||
+ backingq = bdev_get_queue(inode->i_bdev);
|
||||
+ blk_queue_max_discard_sectors(q,
|
||||
+ backingq->limits.max_write_zeroes_sectors);
|
||||
+
|
||||
+ blk_queue_max_write_zeroes_sectors(q,
|
||||
+ backingq->limits.max_write_zeroes_sectors);
|
||||
|
||||
/*
|
||||
* We use punch hole to reclaim the free space used by the
|
||||
@@ -869,22 +885,24 @@ static void loop_config_discard(struct l
|
||||
* encryption is enabled, because it may give an attacker
|
||||
* useful information.
|
||||
*/
|
||||
- if ((!file->f_op->fallocate) ||
|
||||
- lo->lo_encrypt_key_size) {
|
||||
+ } else if ((!file->f_op->fallocate) || lo->lo_encrypt_key_size) {
|
||||
q->limits.discard_granularity = 0;
|
||||
q->limits.discard_alignment = 0;
|
||||
blk_queue_max_discard_sectors(q, 0);
|
||||
blk_queue_max_write_zeroes_sectors(q, 0);
|
||||
- blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
|
||||
- return;
|
||||
- }
|
||||
|
||||
- q->limits.discard_granularity = inode->i_sb->s_blocksize;
|
||||
- q->limits.discard_alignment = 0;
|
||||
+ } else {
|
||||
+ q->limits.discard_granularity = inode->i_sb->s_blocksize;
|
||||
+ q->limits.discard_alignment = 0;
|
||||
|
||||
- blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
|
||||
- blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
|
||||
- blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
|
||||
+ blk_queue_max_discard_sectors(q, UINT_MAX >> 9);
|
||||
+ blk_queue_max_write_zeroes_sectors(q, UINT_MAX >> 9);
|
||||
+ }
|
||||
+
|
||||
+ if (q->limits.max_write_zeroes_sectors)
|
||||
+ blk_queue_flag_set(QUEUE_FLAG_DISCARD, q);
|
||||
+ else
|
||||
+ blk_queue_flag_clear(QUEUE_FLAG_DISCARD, q);
|
||||
}
|
||||
|
||||
static void loop_unprepare_queue(struct loop_device *lo)
|
||||
@ -0,0 +1,82 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:18:54 +0200
|
||||
Subject: bridge: only accept EAP locally
|
||||
|
||||
When bridging, do not forward EAP frames to other ports, only deliver
|
||||
them locally, regardless of the state.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
[add disable_eap_hack sysfs attribute]
|
||||
Signed-off-by: Etienne Champetier <champetier.etienne@gmail.com>
|
||||
---
|
||||
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -103,10 +103,14 @@ int br_handle_frame_finish(struct net *n
|
||||
}
|
||||
}
|
||||
|
||||
+ BR_INPUT_SKB_CB(skb)->brdev = br->dev;
|
||||
+
|
||||
+ if (skb->protocol == htons(ETH_P_PAE) && !br->disable_eap_hack)
|
||||
+ return br_pass_frame_up(skb);
|
||||
+
|
||||
if (p->state == BR_STATE_LEARNING)
|
||||
goto drop;
|
||||
|
||||
- BR_INPUT_SKB_CB(skb)->brdev = br->dev;
|
||||
BR_INPUT_SKB_CB(skb)->src_port_isolated = !!(p->flags & BR_ISOLATED);
|
||||
|
||||
if (IS_ENABLED(CONFIG_INET) &&
|
||||
--- a/net/bridge/br_private.h
|
||||
+++ b/net/bridge/br_private.h
|
||||
@@ -345,6 +345,8 @@ struct net_bridge {
|
||||
u16 group_fwd_mask;
|
||||
u16 group_fwd_mask_required;
|
||||
|
||||
+ bool disable_eap_hack;
|
||||
+
|
||||
/* STP */
|
||||
bridge_id designated_root;
|
||||
bridge_id bridge_id;
|
||||
--- a/net/bridge/br_sysfs_br.c
|
||||
+++ b/net/bridge/br_sysfs_br.c
|
||||
@@ -166,6 +166,30 @@ static ssize_t group_fwd_mask_store(stru
|
||||
}
|
||||
static DEVICE_ATTR_RW(group_fwd_mask);
|
||||
|
||||
+static ssize_t disable_eap_hack_show(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ char *buf)
|
||||
+{
|
||||
+ struct net_bridge *br = to_bridge(d);
|
||||
+ return sprintf(buf, "%u\n", br->disable_eap_hack);
|
||||
+}
|
||||
+
|
||||
+static int set_disable_eap_hack(struct net_bridge *br, unsigned long val)
|
||||
+{
|
||||
+ br->disable_eap_hack = !!val;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static ssize_t disable_eap_hack_store(struct device *d,
|
||||
+ struct device_attribute *attr,
|
||||
+ const char *buf,
|
||||
+ size_t len)
|
||||
+{
|
||||
+ return store_bridge_parm(d, buf, len, set_disable_eap_hack);
|
||||
+}
|
||||
+static DEVICE_ATTR_RW(disable_eap_hack);
|
||||
+
|
||||
static ssize_t priority_show(struct device *d, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
@@ -851,6 +875,7 @@ static struct attribute *bridge_attrs[]
|
||||
&dev_attr_ageing_time.attr,
|
||||
&dev_attr_stp_state.attr,
|
||||
&dev_attr_group_fwd_mask.attr,
|
||||
+ &dev_attr_disable_eap_hack.attr,
|
||||
&dev_attr_priority.attr,
|
||||
&dev_attr_bridge_id.attr,
|
||||
&dev_attr_root_id.attr,
|
||||
@ -0,0 +1,212 @@
|
||||
From eda40b8c8c82e0f2789d6bc8bf63846dce2e8f32 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Date: Sat, 23 Mar 2019 09:29:49 +0000
|
||||
Subject: [PATCH] netfilter: connmark: introduce set-dscpmark
|
||||
|
||||
set-dscpmark is a method of storing the DSCP of an ip packet into
|
||||
conntrack mark. In combination with a suitable tc filter action
|
||||
(act_ctinfo) DSCP values are able to be stored in the mark on egress and
|
||||
restored on ingress across links that otherwise alter or bleach DSCP.
|
||||
|
||||
This is useful for qdiscs such as CAKE which are able to shape according
|
||||
to policies based on DSCP.
|
||||
|
||||
Ingress classification is traditionally a challenging task since
|
||||
iptables rules haven't yet run and tc filter/eBPF programs are pre-NAT
|
||||
lookups, hence are unable to see internal IPv4 addresses as used on the
|
||||
typical home masquerading gateway.
|
||||
|
||||
x_tables CONNMARK set-dscpmark target solves the problem of storing the
|
||||
DSCP to the conntrack mark in a way suitable for the new act_ctinfo tc
|
||||
action to restore.
|
||||
|
||||
The set-dscpmark option accepts 2 parameters, a 32bit 'dscpmask' and a
|
||||
32bit 'statemask'. The dscp mask must be 6 contiguous bits and
|
||||
represents the area where the DSCP will be stored in the connmark. The
|
||||
state mask is a minimum 1 bit length mask that must not overlap with the
|
||||
dscpmask. It represents a flag which is set when the DSCP has been
|
||||
stored in the conntrack mark. This is useful to implement a 'one shot'
|
||||
iptables based classification where the 'complicated' iptables rules are
|
||||
only run once to classify the connection on initial (egress) packet and
|
||||
subsequent packets are all marked/restored with the same DSCP. A state
|
||||
mask of zero disables the setting of a status bit/s.
|
||||
|
||||
example syntax with a suitably modified iptables user space application:
|
||||
|
||||
iptables -A QOS_MARK_eth0 -t mangle -j CONNMARK --set-dscpmark 0xfc000000/0x01000000
|
||||
|
||||
Would store the DSCP in the top 6 bits of the 32bit mark field, and use
|
||||
the LSB of the top byte as the 'DSCP has been stored' marker.
|
||||
|
||||
|----0xFC----conntrack mark----000000---|
|
||||
| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
|
||||
| DSCP | unused | flag |unused |
|
||||
|-----------------------0x01---000000---|
|
||||
^ ^
|
||||
| |
|
||||
---| Conditional flag
|
||||
| set this when dscp
|
||||
|-ip diffserv-| stored in mark
|
||||
| 6 bits |
|
||||
|-------------|
|
||||
|
||||
an identically configured tc action to restore looks like:
|
||||
|
||||
tc filter show dev eth0 ingress
|
||||
filter parent ffff: protocol all pref 10 u32 chain 0
|
||||
filter parent ffff: protocol all pref 10 u32 chain 0 fh 800: ht divisor 1
|
||||
filter parent ffff: protocol all pref 10 u32 chain 0 fh 800::800 order 2048 key ht 800 bkt 0 flowid 1: not_in_hw
|
||||
match 00000000/00000000 at 0
|
||||
action order 1: ctinfo zone 0 pipe
|
||||
index 2 ref 1 bind 1 dscp 0xfc000000/0x1000000
|
||||
|
||||
action order 2: mirred (Egress Redirect to device ifb4eth0) stolen
|
||||
index 1 ref 1 bind 1
|
||||
|
||||
|----0xFC----conntrack mark----000000---|
|
||||
| Bits 31-26 | bit 25 | bit24 |~~~ Bit 0|
|
||||
| DSCP | unused | flag |unused |
|
||||
|-----------------------0x01---000000---|
|
||||
| |
|
||||
| |
|
||||
---| Conditional flag
|
||||
v only restore if set
|
||||
|-ip diffserv-|
|
||||
| 6 bits |
|
||||
|-------------|
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
include/uapi/linux/netfilter/xt_connmark.h | 10 ++++
|
||||
net/netfilter/xt_connmark.c | 55 ++++++++++++++++++----
|
||||
2 files changed, 57 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/include/uapi/linux/netfilter/xt_connmark.h
|
||||
+++ b/include/uapi/linux/netfilter/xt_connmark.h
|
||||
@@ -20,6 +20,11 @@ enum {
|
||||
};
|
||||
|
||||
enum {
|
||||
+ XT_CONNMARK_VALUE = (1 << 0),
|
||||
+ XT_CONNMARK_DSCP = (1 << 1)
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
D_SHIFT_LEFT = 0,
|
||||
D_SHIFT_RIGHT,
|
||||
};
|
||||
@@ -34,6 +39,11 @@ struct xt_connmark_tginfo2 {
|
||||
__u8 shift_dir, shift_bits, mode;
|
||||
};
|
||||
|
||||
+struct xt_connmark_tginfo3 {
|
||||
+ __u32 ctmark, ctmask, nfmask;
|
||||
+ __u8 shift_dir, shift_bits, mode, func;
|
||||
+};
|
||||
+
|
||||
struct xt_connmark_mtinfo1 {
|
||||
__u32 mark, mask;
|
||||
__u8 invert;
|
||||
--- a/net/netfilter/xt_connmark.c
|
||||
+++ b/net/netfilter/xt_connmark.c
|
||||
@@ -24,12 +24,13 @@ MODULE_ALIAS("ipt_connmark");
|
||||
MODULE_ALIAS("ip6t_connmark");
|
||||
|
||||
static unsigned int
|
||||
-connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo2 *info)
|
||||
+connmark_tg_shift(struct sk_buff *skb, const struct xt_connmark_tginfo3 *info)
|
||||
{
|
||||
enum ip_conntrack_info ctinfo;
|
||||
u_int32_t new_targetmark;
|
||||
struct nf_conn *ct;
|
||||
u_int32_t newmark;
|
||||
+ u_int8_t dscp;
|
||||
|
||||
ct = nf_ct_get(skb, &ctinfo);
|
||||
if (ct == NULL)
|
||||
@@ -37,12 +38,24 @@ connmark_tg_shift(struct sk_buff *skb, c
|
||||
|
||||
switch (info->mode) {
|
||||
case XT_CONNMARK_SET:
|
||||
- newmark = (ct->mark & ~info->ctmask) ^ info->ctmark;
|
||||
- if (info->shift_dir == D_SHIFT_RIGHT)
|
||||
- newmark >>= info->shift_bits;
|
||||
- else
|
||||
- newmark <<= info->shift_bits;
|
||||
+ newmark = ct->mark;
|
||||
+ if (info->func & XT_CONNMARK_VALUE) {
|
||||
+ newmark = (newmark & ~info->ctmask) ^ info->ctmark;
|
||||
+ if (info->shift_dir == D_SHIFT_RIGHT)
|
||||
+ newmark >>= info->shift_bits;
|
||||
+ else
|
||||
+ newmark <<= info->shift_bits;
|
||||
+ } else if (info->func & XT_CONNMARK_DSCP) {
|
||||
+ if (skb->protocol == htons(ETH_P_IP))
|
||||
+ dscp = ipv4_get_dsfield(ip_hdr(skb)) >> 2;
|
||||
+ else if (skb->protocol == htons(ETH_P_IPV6))
|
||||
+ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) >> 2;
|
||||
+ else /* protocol doesn't have diffserv */
|
||||
+ break;
|
||||
|
||||
+ newmark = (newmark & ~info->ctmark) |
|
||||
+ (info->ctmask | (dscp << info->shift_bits));
|
||||
+ }
|
||||
if (ct->mark != newmark) {
|
||||
ct->mark = newmark;
|
||||
nf_conntrack_event_cache(IPCT_MARK, ct);
|
||||
@@ -81,20 +94,36 @@ static unsigned int
|
||||
connmark_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_connmark_tginfo1 *info = par->targinfo;
|
||||
- const struct xt_connmark_tginfo2 info2 = {
|
||||
+ const struct xt_connmark_tginfo3 info3 = {
|
||||
.ctmark = info->ctmark,
|
||||
.ctmask = info->ctmask,
|
||||
.nfmask = info->nfmask,
|
||||
.mode = info->mode,
|
||||
+ .func = XT_CONNMARK_VALUE
|
||||
};
|
||||
|
||||
- return connmark_tg_shift(skb, &info2);
|
||||
+ return connmark_tg_shift(skb, &info3);
|
||||
}
|
||||
|
||||
static unsigned int
|
||||
connmark_tg_v2(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
{
|
||||
const struct xt_connmark_tginfo2 *info = par->targinfo;
|
||||
+ const struct xt_connmark_tginfo3 info3 = {
|
||||
+ .ctmark = info->ctmark,
|
||||
+ .ctmask = info->ctmask,
|
||||
+ .nfmask = info->nfmask,
|
||||
+ .mode = info->mode,
|
||||
+ .func = XT_CONNMARK_VALUE
|
||||
+ };
|
||||
+
|
||||
+ return connmark_tg_shift(skb, &info3);
|
||||
+}
|
||||
+
|
||||
+static unsigned int
|
||||
+connmark_tg_v3(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
+{
|
||||
+ const struct xt_connmark_tginfo3 *info = par->targinfo;
|
||||
|
||||
return connmark_tg_shift(skb, info);
|
||||
}
|
||||
@@ -165,6 +194,16 @@ static struct xt_target connmark_tg_reg[
|
||||
.targetsize = sizeof(struct xt_connmark_tginfo2),
|
||||
.destroy = connmark_tg_destroy,
|
||||
.me = THIS_MODULE,
|
||||
+ },
|
||||
+ {
|
||||
+ .name = "CONNMARK",
|
||||
+ .revision = 3,
|
||||
+ .family = NFPROTO_UNSPEC,
|
||||
+ .checkentry = connmark_tg_check,
|
||||
+ .target = connmark_tg_v3,
|
||||
+ .targetsize = sizeof(struct xt_connmark_tginfo3),
|
||||
+ .destroy = connmark_tg_destroy,
|
||||
+ .me = THIS_MODULE,
|
||||
}
|
||||
};
|
||||
|
||||
70
target/linux/generic/hack-5.4/647-netfilter-flow-acct.patch
Normal file
70
target/linux/generic/hack-5.4/647-netfilter-flow-acct.patch
Normal file
@ -0,0 +1,70 @@
|
||||
--- a/include/net/netfilter/nf_flow_table.h
|
||||
+++ b/include/net/netfilter/nf_flow_table.h
|
||||
@@ -158,6 +158,8 @@ struct nf_flow_table_hw {
|
||||
int nf_flow_table_hw_register(const struct nf_flow_table_hw *offload);
|
||||
void nf_flow_table_hw_unregister(const struct nf_flow_table_hw *offload);
|
||||
|
||||
+void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir);
|
||||
+
|
||||
extern struct work_struct nf_flow_offload_hw_work;
|
||||
|
||||
#define MODULE_ALIAS_NF_FLOWTABLE(family) \
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_conntrack_l4proto.h>
|
||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||
+#include <net/netfilter/nf_conntrack_acct.h>
|
||||
|
||||
struct flow_offload_entry {
|
||||
struct flow_offload flow;
|
||||
@@ -164,6 +165,22 @@ void flow_offload_free(struct flow_offlo
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flow_offload_free);
|
||||
|
||||
+void nf_flow_table_acct(struct flow_offload *flow, struct sk_buff *skb, int dir)
|
||||
+{
|
||||
+ struct flow_offload_entry *entry;
|
||||
+ struct nf_conn_acct *acct;
|
||||
+
|
||||
+ entry = container_of(flow, struct flow_offload_entry, flow);
|
||||
+ acct = nf_conn_acct_find(entry->ct);
|
||||
+ if (acct) {
|
||||
+ struct nf_conn_counter *counter = acct->counter;
|
||||
+
|
||||
+ atomic64_inc(&counter[dir].packets);
|
||||
+ atomic64_add(skb->len, &counter[dir].bytes);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_table_acct);
|
||||
+
|
||||
static u32 flow_offload_hash(const void *data, u32 len, u32 seed)
|
||||
{
|
||||
const struct flow_offload_tuple *tuple = data;
|
||||
--- a/net/netfilter/nf_flow_table_ip.c
|
||||
+++ b/net/netfilter/nf_flow_table_ip.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <net/ip6_route.h>
|
||||
#include <net/neighbour.h>
|
||||
#include <net/netfilter/nf_flow_table.h>
|
||||
+
|
||||
/* For layer 4 checksum field offset. */
|
||||
#include <linux/tcp.h>
|
||||
#include <linux/udp.h>
|
||||
@@ -296,6 +297,7 @@ nf_flow_offload_ip_hook(void *priv, stru
|
||||
skb->dev = outdev;
|
||||
nexthop = rt_nexthop(rt, flow->tuplehash[!dir].tuple.src_v4.s_addr);
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
+ nf_flow_table_acct(flow, skb, dir);
|
||||
neigh_xmit(NEIGH_ARP_TABLE, outdev, &nexthop, skb);
|
||||
|
||||
return NF_STOLEN;
|
||||
@@ -526,6 +528,7 @@ nf_flow_offload_ipv6_hook(void *priv, st
|
||||
skb->dev = outdev;
|
||||
nexthop = rt6_nexthop(rt, &flow->tuplehash[!dir].tuple.src_v6);
|
||||
skb_dst_set_noref(skb, &rt->dst);
|
||||
+ nf_flow_table_acct(flow, skb, dir);
|
||||
neigh_xmit(NEIGH_ND_TABLE, outdev, nexthop, skb);
|
||||
|
||||
return NF_STOLEN;
|
||||
@ -0,0 +1,589 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Tue, 20 Feb 2018 15:56:02 +0100
|
||||
Subject: [PATCH] netfilter: add xt_OFFLOAD target
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
create mode 100644 net/netfilter/xt_OFFLOAD.c
|
||||
|
||||
--- a/net/ipv4/netfilter/Kconfig
|
||||
+++ b/net/ipv4/netfilter/Kconfig
|
||||
@@ -56,8 +56,6 @@ config NF_TABLES_ARP
|
||||
help
|
||||
This option enables the ARP support for nf_tables.
|
||||
|
||||
-endif # NF_TABLES
|
||||
-
|
||||
config NF_FLOW_TABLE_IPV4
|
||||
tristate "Netfilter flow table IPv4 module"
|
||||
depends on NF_FLOW_TABLE
|
||||
@@ -66,6 +64,8 @@ config NF_FLOW_TABLE_IPV4
|
||||
|
||||
To compile it as a module, choose M here.
|
||||
|
||||
+endif # NF_TABLES
|
||||
+
|
||||
config NF_DUP_IPV4
|
||||
tristate "Netfilter IPv4 packet duplication to alternate destination"
|
||||
depends on !NF_CONNTRACK || NF_CONNTRACK
|
||||
--- a/net/ipv6/netfilter/Kconfig
|
||||
+++ b/net/ipv6/netfilter/Kconfig
|
||||
@@ -45,7 +45,6 @@ config NFT_FIB_IPV6
|
||||
multicast or blackhole.
|
||||
|
||||
endif # NF_TABLES_IPV6
|
||||
-endif # NF_TABLES
|
||||
|
||||
config NF_FLOW_TABLE_IPV6
|
||||
tristate "Netfilter flow table IPv6 module"
|
||||
@@ -55,6 +54,8 @@ config NF_FLOW_TABLE_IPV6
|
||||
|
||||
To compile it as a module, choose M here.
|
||||
|
||||
+endif # NF_TABLES
|
||||
+
|
||||
config NF_DUP_IPV6
|
||||
tristate "Netfilter IPv6 packet duplication to alternate destination"
|
||||
depends on !NF_CONNTRACK || NF_CONNTRACK
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -702,8 +702,6 @@ config NFT_FIB_NETDEV
|
||||
|
||||
endif # NF_TABLES_NETDEV
|
||||
|
||||
-endif # NF_TABLES
|
||||
-
|
||||
config NF_FLOW_TABLE_INET
|
||||
tristate "Netfilter flow table mixed IPv4/IPv6 module"
|
||||
depends on NF_FLOW_TABLE
|
||||
@@ -712,11 +710,12 @@ config NF_FLOW_TABLE_INET
|
||||
|
||||
To compile it as a module, choose M here.
|
||||
|
||||
+endif # NF_TABLES
|
||||
+
|
||||
config NF_FLOW_TABLE
|
||||
tristate "Netfilter flow table module"
|
||||
depends on NETFILTER_INGRESS
|
||||
depends on NF_CONNTRACK
|
||||
- depends on NF_TABLES
|
||||
help
|
||||
This option adds the flow table core infrastructure.
|
||||
|
||||
@@ -1005,6 +1004,15 @@ config NETFILTER_XT_TARGET_NOTRACK
|
||||
depends on NETFILTER_ADVANCED
|
||||
select NETFILTER_XT_TARGET_CT
|
||||
|
||||
+config NETFILTER_XT_TARGET_FLOWOFFLOAD
|
||||
+ tristate '"FLOWOFFLOAD" target support'
|
||||
+ depends on NF_FLOW_TABLE
|
||||
+ depends on NETFILTER_INGRESS
|
||||
+ help
|
||||
+ This option adds a `FLOWOFFLOAD' target, which uses the nf_flow_offload
|
||||
+ module to speed up processing of packets by bypassing the usual
|
||||
+ netfilter chains
|
||||
+
|
||||
config NETFILTER_XT_TARGET_RATEEST
|
||||
tristate '"RATEEST" target support'
|
||||
depends on NETFILTER_ADVANCED
|
||||
--- a/net/netfilter/Makefile
|
||||
+++ b/net/netfilter/Makefile
|
||||
@@ -144,6 +144,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CLASSIF
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CONNSECMARK) += xt_CONNSECMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += xt_CT.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o
|
||||
+obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o
|
||||
obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o
|
||||
--- /dev/null
|
||||
+++ b/net/netfilter/xt_FLOWOFFLOAD.c
|
||||
@@ -0,0 +1,427 @@
|
||||
+/*
|
||||
+ * Copyright (C) 2018 Felix Fietkau <nbd@nbd.name>
|
||||
+ *
|
||||
+ * 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/init.h>
|
||||
+#include <linux/netfilter.h>
|
||||
+#include <linux/netfilter/xt_FLOWOFFLOAD.h>
|
||||
+#include <net/ip.h>
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_extend.h>
|
||||
+#include <net/netfilter/nf_conntrack_helper.h>
|
||||
+#include <net/netfilter/nf_flow_table.h>
|
||||
+
|
||||
+static struct nf_flowtable nf_flowtable;
|
||||
+static HLIST_HEAD(hooks);
|
||||
+static DEFINE_SPINLOCK(hooks_lock);
|
||||
+static struct delayed_work hook_work;
|
||||
+
|
||||
+struct xt_flowoffload_hook {
|
||||
+ struct hlist_node list;
|
||||
+ struct nf_hook_ops ops;
|
||||
+ struct net *net;
|
||||
+ bool registered;
|
||||
+ bool used;
|
||||
+};
|
||||
+
|
||||
+static unsigned int
|
||||
+xt_flowoffload_net_hook(void *priv, struct sk_buff *skb,
|
||||
+ const struct nf_hook_state *state)
|
||||
+{
|
||||
+ switch (skb->protocol) {
|
||||
+ case htons(ETH_P_IP):
|
||||
+ return nf_flow_offload_ip_hook(priv, skb, state);
|
||||
+ case htons(ETH_P_IPV6):
|
||||
+ return nf_flow_offload_ipv6_hook(priv, skb, state);
|
||||
+ }
|
||||
+
|
||||
+ return NF_ACCEPT;
|
||||
+}
|
||||
+
|
||||
+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
|
||||
+ void (*iter)(struct flow_offload *flow, void *data),
|
||||
+ void *data);
|
||||
+
|
||||
+static int
|
||||
+xt_flowoffload_create_hook(struct net_device *dev)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+ struct nf_hook_ops *ops;
|
||||
+
|
||||
+ hook = kzalloc(sizeof(*hook), GFP_ATOMIC);
|
||||
+ if (!hook)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ ops = &hook->ops;
|
||||
+ ops->pf = NFPROTO_NETDEV;
|
||||
+ ops->hooknum = NF_NETDEV_INGRESS;
|
||||
+ ops->priority = 10;
|
||||
+ ops->priv = &nf_flowtable;
|
||||
+ ops->hook = xt_flowoffload_net_hook;
|
||||
+ ops->dev = dev;
|
||||
+
|
||||
+ hlist_add_head(&hook->list, &hooks);
|
||||
+ mod_delayed_work(system_power_efficient_wq, &hook_work, 0);
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct xt_flowoffload_hook *
|
||||
+flow_offload_lookup_hook(struct net_device *dev)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+
|
||||
+ hlist_for_each_entry(hook, &hooks, list) {
|
||||
+ if (hook->ops.dev == dev)
|
||||
+ return hook;
|
||||
+ }
|
||||
+
|
||||
+ return NULL;
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xt_flowoffload_check_device(struct net_device *dev)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ hook = flow_offload_lookup_hook(dev);
|
||||
+ if (hook)
|
||||
+ hook->used = true;
|
||||
+ else
|
||||
+ xt_flowoffload_create_hook(dev);
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xt_flowoffload_register_hooks(void)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+
|
||||
+restart:
|
||||
+ hlist_for_each_entry(hook, &hooks, list) {
|
||||
+ if (hook->registered)
|
||||
+ continue;
|
||||
+
|
||||
+ hook->registered = true;
|
||||
+ hook->net = dev_net(hook->ops.dev);
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+ nf_register_net_hook(hook->net, &hook->ops);
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ goto restart;
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xt_flowoffload_cleanup_hooks(void)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+
|
||||
+restart:
|
||||
+ hlist_for_each_entry(hook, &hooks, list) {
|
||||
+ if (hook->used || !hook->registered)
|
||||
+ continue;
|
||||
+
|
||||
+ hlist_del(&hook->list);
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+ nf_unregister_net_hook(hook->net, &hook->ops);
|
||||
+ kfree(hook);
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ goto restart;
|
||||
+ }
|
||||
+
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xt_flowoffload_check_hook(struct flow_offload *flow, void *data)
|
||||
+{
|
||||
+ struct flow_offload_tuple *tuple = &flow->tuplehash[0].tuple;
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+ bool *found = data;
|
||||
+ struct rtable *rt = (struct rtable *)tuple->dst_cache;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ hlist_for_each_entry(hook, &hooks, list) {
|
||||
+ if (hook->ops.dev->ifindex != tuple->iifidx &&
|
||||
+ hook->ops.dev->ifindex != rt->dst.dev->ifindex)
|
||||
+ continue;
|
||||
+
|
||||
+ hook->used = true;
|
||||
+ *found = true;
|
||||
+ }
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+}
|
||||
+
|
||||
+static void
|
||||
+xt_flowoffload_hook_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook;
|
||||
+ bool found = false;
|
||||
+ int err;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ xt_flowoffload_register_hooks();
|
||||
+ hlist_for_each_entry(hook, &hooks, list)
|
||||
+ hook->used = false;
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+
|
||||
+ err = nf_flow_table_iterate(&nf_flowtable, xt_flowoffload_check_hook,
|
||||
+ &found);
|
||||
+ if (err && err != -EAGAIN)
|
||||
+ goto out;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ xt_flowoffload_cleanup_hooks();
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+
|
||||
+out:
|
||||
+ if (found)
|
||||
+ queue_delayed_work(system_power_efficient_wq, &hook_work, HZ);
|
||||
+}
|
||||
+
|
||||
+static bool
|
||||
+xt_flowoffload_skip(struct sk_buff *skb, int family)
|
||||
+{
|
||||
+ if (skb_sec_path(skb))
|
||||
+ return true;
|
||||
+
|
||||
+ if (family == NFPROTO_IPV4) {
|
||||
+ const struct ip_options *opt = &(IPCB(skb)->opt);
|
||||
+
|
||||
+ if (unlikely(opt->optlen))
|
||||
+ return true;
|
||||
+ }
|
||||
+
|
||||
+ return false;
|
||||
+}
|
||||
+
|
||||
+static struct dst_entry *
|
||||
+xt_flowoffload_dst(const struct nf_conn *ct, enum ip_conntrack_dir dir,
|
||||
+ const struct xt_action_param *par, int ifindex)
|
||||
+{
|
||||
+ struct dst_entry *dst = NULL;
|
||||
+ struct flowi fl;
|
||||
+
|
||||
+ memset(&fl, 0, sizeof(fl));
|
||||
+ switch (xt_family(par)) {
|
||||
+ case NFPROTO_IPV4:
|
||||
+ fl.u.ip4.daddr = ct->tuplehash[dir].tuple.src.u3.ip;
|
||||
+ fl.u.ip4.flowi4_oif = ifindex;
|
||||
+ break;
|
||||
+ case NFPROTO_IPV6:
|
||||
+ fl.u.ip6.saddr = ct->tuplehash[dir].tuple.dst.u3.in6;
|
||||
+ fl.u.ip6.daddr = ct->tuplehash[dir].tuple.src.u3.in6;
|
||||
+ fl.u.ip6.flowi6_oif = ifindex;
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ nf_route(xt_net(par), &dst, &fl, false, xt_family(par));
|
||||
+
|
||||
+ return dst;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+xt_flowoffload_route(struct sk_buff *skb, const struct nf_conn *ct,
|
||||
+ const struct xt_action_param *par,
|
||||
+ struct nf_flow_route *route, enum ip_conntrack_dir dir)
|
||||
+{
|
||||
+ struct dst_entry *this_dst, *other_dst;
|
||||
+
|
||||
+ this_dst = xt_flowoffload_dst(ct, !dir, par, xt_out(par)->ifindex);
|
||||
+ other_dst = xt_flowoffload_dst(ct, dir, par, xt_in(par)->ifindex);
|
||||
+
|
||||
+ route->tuple[dir].dst = this_dst;
|
||||
+ route->tuple[!dir].dst = other_dst;
|
||||
+
|
||||
+ if (!this_dst || !other_dst)
|
||||
+ return -ENOENT;
|
||||
+
|
||||
+ if (dst_xfrm(this_dst) || dst_xfrm(other_dst))
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static unsigned int
|
||||
+flowoffload_tg(struct sk_buff *skb, const struct xt_action_param *par)
|
||||
+{
|
||||
+ const struct xt_flowoffload_target_info *info = par->targinfo;
|
||||
+ struct tcphdr _tcph, *tcph = NULL;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ enum ip_conntrack_dir dir;
|
||||
+ struct nf_flow_route route;
|
||||
+ struct flow_offload *flow = NULL;
|
||||
+ struct nf_conn *ct;
|
||||
+ struct net *net;
|
||||
+
|
||||
+ if (xt_flowoffload_skip(skb, xt_family(par)))
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (ct == NULL)
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ switch (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.protonum) {
|
||||
+ case IPPROTO_TCP:
|
||||
+ if (ct->proto.tcp.state != TCP_CONNTRACK_ESTABLISHED)
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ tcph = skb_header_pointer(skb, par->thoff,
|
||||
+ sizeof(_tcph), &_tcph);
|
||||
+ if (unlikely(!tcph || tcph->fin || tcph->rst))
|
||||
+ return XT_CONTINUE;
|
||||
+ break;
|
||||
+ case IPPROTO_UDP:
|
||||
+ break;
|
||||
+ default:
|
||||
+ return XT_CONTINUE;
|
||||
+ }
|
||||
+
|
||||
+ if (nf_ct_ext_exist(ct, NF_CT_EXT_HELPER) ||
|
||||
+ ct->status & IPS_SEQ_ADJUST)
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ if (!nf_ct_is_confirmed(ct))
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ if (!xt_in(par) || !xt_out(par))
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ if (test_and_set_bit(IPS_OFFLOAD_BIT, &ct->status))
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+ dir = CTINFO2DIR(ctinfo);
|
||||
+
|
||||
+ if (xt_flowoffload_route(skb, ct, par, &route, dir) == 0)
|
||||
+ flow = flow_offload_alloc(ct, &route);
|
||||
+
|
||||
+ dst_release(route.tuple[dir].dst);
|
||||
+ dst_release(route.tuple[!dir].dst);
|
||||
+
|
||||
+ if (!flow)
|
||||
+ goto err_flow_route;
|
||||
+
|
||||
+ if (tcph) {
|
||||
+ ct->proto.tcp.seen[0].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
|
||||
+ ct->proto.tcp.seen[1].flags |= IP_CT_TCP_FLAG_BE_LIBERAL;
|
||||
+ }
|
||||
+
|
||||
+ if (flow_offload_add(&nf_flowtable, flow) < 0)
|
||||
+ goto err_flow_add;
|
||||
+
|
||||
+ xt_flowoffload_check_device(xt_in(par));
|
||||
+ xt_flowoffload_check_device(xt_out(par));
|
||||
+
|
||||
+ net = read_pnet(&nf_flowtable.ft_net);
|
||||
+ if (!net)
|
||||
+ write_pnet(&nf_flowtable.ft_net, xt_net(par));
|
||||
+
|
||||
+ if (info->flags & XT_FLOWOFFLOAD_HW)
|
||||
+ nf_flow_offload_hw_add(xt_net(par), flow, ct);
|
||||
+
|
||||
+ return XT_CONTINUE;
|
||||
+
|
||||
+err_flow_add:
|
||||
+ flow_offload_free(flow);
|
||||
+err_flow_route:
|
||||
+ clear_bit(IPS_OFFLOAD_BIT, &ct->status);
|
||||
+ return XT_CONTINUE;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+static int flowoffload_chk(const struct xt_tgchk_param *par)
|
||||
+{
|
||||
+ struct xt_flowoffload_target_info *info = par->targinfo;
|
||||
+
|
||||
+ if (info->flags & ~XT_FLOWOFFLOAD_MASK)
|
||||
+ return -EINVAL;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static struct xt_target offload_tg_reg __read_mostly = {
|
||||
+ .family = NFPROTO_UNSPEC,
|
||||
+ .name = "FLOWOFFLOAD",
|
||||
+ .revision = 0,
|
||||
+ .targetsize = sizeof(struct xt_flowoffload_target_info),
|
||||
+ .usersize = sizeof(struct xt_flowoffload_target_info),
|
||||
+ .checkentry = flowoffload_chk,
|
||||
+ .target = flowoffload_tg,
|
||||
+ .me = THIS_MODULE,
|
||||
+};
|
||||
+
|
||||
+static int xt_flowoffload_table_init(struct nf_flowtable *table)
|
||||
+{
|
||||
+ table->flags = NF_FLOWTABLE_F_HW;
|
||||
+ nf_flow_table_init(table);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void xt_flowoffload_table_cleanup(struct nf_flowtable *table)
|
||||
+{
|
||||
+ nf_flow_table_free(table);
|
||||
+}
|
||||
+
|
||||
+static int flow_offload_netdev_event(struct notifier_block *this,
|
||||
+ unsigned long event, void *ptr)
|
||||
+{
|
||||
+ struct xt_flowoffload_hook *hook = NULL;
|
||||
+ struct net_device *dev = netdev_notifier_info_to_dev(ptr);
|
||||
+
|
||||
+ if (event != NETDEV_UNREGISTER)
|
||||
+ return NOTIFY_DONE;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ hook = flow_offload_lookup_hook(dev);
|
||||
+ if (hook) {
|
||||
+ hlist_del(&hook->list);
|
||||
+ }
|
||||
+ spin_unlock_bh(&hooks_lock);
|
||||
+ if (hook) {
|
||||
+ nf_unregister_net_hook(hook->net, &hook->ops);
|
||||
+ kfree(hook);
|
||||
+ }
|
||||
+
|
||||
+ nf_flow_table_cleanup(dev);
|
||||
+
|
||||
+ return NOTIFY_DONE;
|
||||
+}
|
||||
+
|
||||
+static struct notifier_block flow_offload_netdev_notifier = {
|
||||
+ .notifier_call = flow_offload_netdev_event,
|
||||
+};
|
||||
+
|
||||
+static int __init xt_flowoffload_tg_init(void)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ register_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
+
|
||||
+ INIT_DELAYED_WORK(&hook_work, xt_flowoffload_hook_work);
|
||||
+
|
||||
+ ret = xt_flowoffload_table_init(&nf_flowtable);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = xt_register_target(&offload_tg_reg);
|
||||
+ if (ret)
|
||||
+ xt_flowoffload_table_cleanup(&nf_flowtable);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static void __exit xt_flowoffload_tg_exit(void)
|
||||
+{
|
||||
+ xt_unregister_target(&offload_tg_reg);
|
||||
+ xt_flowoffload_table_cleanup(&nf_flowtable);
|
||||
+ unregister_netdevice_notifier(&flow_offload_netdev_notifier);
|
||||
+}
|
||||
+
|
||||
+MODULE_LICENSE("GPL");
|
||||
+module_init(xt_flowoffload_tg_init);
|
||||
+module_exit(xt_flowoffload_tg_exit);
|
||||
--- a/net/netfilter/nf_flow_table_core.c
|
||||
+++ b/net/netfilter/nf_flow_table_core.c
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/ip.h>
|
||||
#include <net/ip6_route.h>
|
||||
-#include <net/netfilter/nf_tables.h>
|
||||
#include <net/netfilter/nf_flow_table.h>
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
@@ -338,8 +337,7 @@ flow_offload_lookup(struct nf_flowtable
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(flow_offload_lookup);
|
||||
|
||||
-static int
|
||||
-nf_flow_table_iterate(struct nf_flowtable *flow_table,
|
||||
+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
|
||||
void (*iter)(struct flow_offload *flow, void *data),
|
||||
void *data)
|
||||
{
|
||||
@@ -372,6 +370,7 @@ nf_flow_table_iterate(struct nf_flowtabl
|
||||
|
||||
return err;
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(nf_flow_table_iterate);
|
||||
|
||||
static void nf_flow_offload_gc_step(struct flow_offload *flow, void *data)
|
||||
{
|
||||
--- /dev/null
|
||||
+++ b/include/uapi/linux/netfilter/xt_FLOWOFFLOAD.h
|
||||
@@ -0,0 +1,17 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
+#ifndef _XT_FLOWOFFLOAD_H
|
||||
+#define _XT_FLOWOFFLOAD_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+enum {
|
||||
+ XT_FLOWOFFLOAD_HW = 1 << 0,
|
||||
+
|
||||
+ XT_FLOWOFFLOAD_MASK = XT_FLOWOFFLOAD_HW
|
||||
+};
|
||||
+
|
||||
+struct xt_flowoffload_target_info {
|
||||
+ __u32 flags;
|
||||
+};
|
||||
+
|
||||
+#endif /* _XT_FLOWOFFLOAD_H */
|
||||
--- a/include/net/netfilter/nf_flow_table.h
|
||||
+++ b/include/net/netfilter/nf_flow_table.h
|
||||
@@ -128,6 +128,10 @@ static inline void flow_offload_dead(str
|
||||
flow->flags |= FLOW_OFFLOAD_DYING;
|
||||
}
|
||||
|
||||
+int nf_flow_table_iterate(struct nf_flowtable *flow_table,
|
||||
+ void (*iter)(struct flow_offload *flow, void *data),
|
||||
+ void *data);
|
||||
+
|
||||
int nf_flow_snat_port(const struct flow_offload *flow,
|
||||
struct sk_buff *skb, unsigned int thoff,
|
||||
u8 protocol, enum flow_offload_tuple_dir dir);
|
||||
24
target/linux/generic/hack-5.4/651-wireless_mesh_header.patch
Normal file
24
target/linux/generic/hack-5.4/651-wireless_mesh_header.patch
Normal file
@ -0,0 +1,24 @@
|
||||
From 6d3bc769657b0ee7c7506dad9911111c4226a7ea Mon Sep 17 00:00:00 2001
|
||||
From: Imre Kaloz <kaloz@openwrt.org>
|
||||
Date: Fri, 7 Jul 2017 17:21:05 +0200
|
||||
Subject: mac80211: increase wireless mesh header size
|
||||
|
||||
lede-commit 3d4466cfd8f75f717efdb1f96fdde3c70d865fc1
|
||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||
---
|
||||
include/linux/netdevice.h | 4 ++--
|
||||
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -138,8 +138,8 @@ static inline bool dev_xmit_complete(int
|
||||
|
||||
#if defined(CONFIG_HYPERV_NET)
|
||||
# define LL_MAX_HEADER 128
|
||||
-#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25)
|
||||
-# if defined(CONFIG_MAC80211_MESH)
|
||||
+#elif defined(CONFIG_WLAN) || IS_ENABLED(CONFIG_AX25) || 1
|
||||
+# if defined(CONFIG_MAC80211_MESH) || 1
|
||||
# define LL_MAX_HEADER 128
|
||||
# else
|
||||
# define LL_MAX_HEADER 96
|
||||
27
target/linux/generic/hack-5.4/660-fq_codel_defaults.patch
Normal file
27
target/linux/generic/hack-5.4/660-fq_codel_defaults.patch
Normal file
@ -0,0 +1,27 @@
|
||||
From a6ccb238939b25851474a279b20367fd24a0e816 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:21:53 +0200
|
||||
Subject: hack: net: fq_codel: tune defaults for small devices
|
||||
|
||||
Assume that x86_64 devices always have a big memory and do not need this
|
||||
optimization compared to devices with only 32 MB or 64 MB RAM.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/sched/sch_fq_codel.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -462,7 +462,11 @@ static int fq_codel_init(struct Qdisc *s
|
||||
|
||||
sch->limit = 10*1024;
|
||||
q->flows_cnt = 1024;
|
||||
+#ifdef CONFIG_X86_64
|
||||
q->memory_limit = 32 << 20; /* 32 MBytes */
|
||||
+#else
|
||||
+ q->memory_limit = 4 << 20; /* 4 MBytes */
|
||||
+#endif
|
||||
q->drop_batch_size = 64;
|
||||
q->quantum = psched_mtu(qdisc_dev(sch));
|
||||
INIT_LIST_HEAD(&q->new_flows);
|
||||
100
target/linux/generic/hack-5.4/661-use_fq_codel_by_default.patch
Normal file
100
target/linux/generic/hack-5.4/661-use_fq_codel_by_default.patch
Normal file
@ -0,0 +1,100 @@
|
||||
From 1d418f7e88035ed7a94073f6354246c66e9193e9 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:22:58 +0200
|
||||
Subject: fq_codel: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/net/sch_generic.h | 3 ++-
|
||||
net/sched/Kconfig | 3 ++-
|
||||
net/sched/sch_api.c | 2 +-
|
||||
net/sched/sch_fq_codel.c | 3 ++-
|
||||
net/sched/sch_generic.c | 4 ++--
|
||||
5 files changed, 9 insertions(+), 6 deletions(-)
|
||||
|
||||
--- a/include/net/sch_generic.h
|
||||
+++ b/include/net/sch_generic.h
|
||||
@@ -569,12 +569,13 @@ extern struct Qdisc_ops noop_qdisc_ops;
|
||||
extern struct Qdisc_ops pfifo_fast_ops;
|
||||
extern struct Qdisc_ops mq_qdisc_ops;
|
||||
extern struct Qdisc_ops noqueue_qdisc_ops;
|
||||
+extern struct Qdisc_ops fq_codel_qdisc_ops;
|
||||
extern const struct Qdisc_ops *default_qdisc_ops;
|
||||
static inline const struct Qdisc_ops *
|
||||
get_default_qdisc_ops(const struct net_device *dev, int ntx)
|
||||
{
|
||||
return ntx < dev->real_num_tx_queues ?
|
||||
- default_qdisc_ops : &pfifo_fast_ops;
|
||||
+ default_qdisc_ops : &fq_codel_qdisc_ops;
|
||||
}
|
||||
|
||||
struct Qdisc_class_common {
|
||||
--- a/net/sched/Kconfig
|
||||
+++ b/net/sched/Kconfig
|
||||
@@ -4,8 +4,9 @@
|
||||
#
|
||||
|
||||
menuconfig NET_SCHED
|
||||
- bool "QoS and/or fair queueing"
|
||||
+ def_bool y
|
||||
select NET_SCH_FIFO
|
||||
+ select NET_SCH_FQ_CODEL
|
||||
---help---
|
||||
When the kernel has several packets to send out over a network
|
||||
device, it has to decide which ones to send first, which ones to
|
||||
--- a/net/sched/sch_api.c
|
||||
+++ b/net/sched/sch_api.c
|
||||
@@ -2271,7 +2271,7 @@ static int __init pktsched_init(void)
|
||||
return err;
|
||||
}
|
||||
|
||||
- register_qdisc(&pfifo_fast_ops);
|
||||
+ register_qdisc(&fq_codel_qdisc_ops);
|
||||
register_qdisc(&pfifo_qdisc_ops);
|
||||
register_qdisc(&bfifo_qdisc_ops);
|
||||
register_qdisc(&pfifo_head_drop_qdisc_ops);
|
||||
--- a/net/sched/sch_fq_codel.c
|
||||
+++ b/net/sched/sch_fq_codel.c
|
||||
@@ -702,7 +702,7 @@ static const struct Qdisc_class_ops fq_c
|
||||
.walk = fq_codel_walk,
|
||||
};
|
||||
|
||||
-static struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
|
||||
+struct Qdisc_ops fq_codel_qdisc_ops __read_mostly = {
|
||||
.cl_ops = &fq_codel_class_ops,
|
||||
.id = "fq_codel",
|
||||
.priv_size = sizeof(struct fq_codel_sched_data),
|
||||
@@ -717,6 +717,7 @@ static struct Qdisc_ops fq_codel_qdisc_o
|
||||
.dump_stats = fq_codel_dump_stats,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
+EXPORT_SYMBOL(fq_codel_qdisc_ops);
|
||||
|
||||
static int __init fq_codel_module_init(void)
|
||||
{
|
||||
--- a/net/sched/sch_generic.c
|
||||
+++ b/net/sched/sch_generic.c
|
||||
@@ -32,7 +32,7 @@
|
||||
#include <net/xfrm.h>
|
||||
|
||||
/* Qdisc to use by default */
|
||||
-const struct Qdisc_ops *default_qdisc_ops = &pfifo_fast_ops;
|
||||
+const struct Qdisc_ops *default_qdisc_ops = &fq_codel_qdisc_ops;
|
||||
EXPORT_SYMBOL(default_qdisc_ops);
|
||||
|
||||
/* Main transmission queue. */
|
||||
@@ -1034,12 +1034,12 @@ static void attach_one_default_qdisc(str
|
||||
void *_unused)
|
||||
{
|
||||
struct Qdisc *qdisc;
|
||||
- const struct Qdisc_ops *ops = default_qdisc_ops;
|
||||
+ const struct Qdisc_ops *ops = &fq_codel_qdisc_ops;
|
||||
|
||||
if (dev->priv_flags & IFF_NO_QUEUE)
|
||||
ops = &noqueue_qdisc_ops;
|
||||
else if(dev->type == ARPHRD_CAN)
|
||||
- ops = &pfifo_fast_ops;
|
||||
+ ops = &fq_codel_qdisc_ops;
|
||||
|
||||
qdisc = qdisc_create_dflt(dev_queue, ops, TC_H_ROOT, NULL);
|
||||
if (!qdisc) {
|
||||
224
target/linux/generic/hack-5.4/662-remove_pfifo_fast.patch
Normal file
224
target/linux/generic/hack-5.4/662-remove_pfifo_fast.patch
Normal file
@ -0,0 +1,224 @@
|
||||
From b531d492d5ef1cf9dba0f4888eb5fd8624a6d762 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:23:42 +0200
|
||||
Subject: net: sched: switch default qdisc from pfifo_fast to fq_codel and remove pfifo_fast
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/sched/sch_generic.c | 140 ------------------------------------------------
|
||||
1 file changed, 140 deletions(-)
|
||||
|
||||
--- a/net/sched/sch_generic.c
|
||||
+++ b/net/sched/sch_generic.c
|
||||
@@ -594,211 +594,6 @@ struct Qdisc_ops noqueue_qdisc_ops __rea
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
-static const u8 prio2band[TC_PRIO_MAX + 1] = {
|
||||
- 1, 2, 2, 2, 1, 2, 0, 0 , 1, 1, 1, 1, 1, 1, 1, 1
|
||||
-};
|
||||
-
|
||||
-/* 3-band FIFO queue: old style, but should be a bit faster than
|
||||
- generic prio+fifo combination.
|
||||
- */
|
||||
-
|
||||
-#define PFIFO_FAST_BANDS 3
|
||||
-
|
||||
-/*
|
||||
- * Private data for a pfifo_fast scheduler containing:
|
||||
- * - rings for priority bands
|
||||
- */
|
||||
-struct pfifo_fast_priv {
|
||||
- struct skb_array q[PFIFO_FAST_BANDS];
|
||||
-};
|
||||
-
|
||||
-static inline struct skb_array *band2list(struct pfifo_fast_priv *priv,
|
||||
- int band)
|
||||
-{
|
||||
- return &priv->q[band];
|
||||
-}
|
||||
-
|
||||
-static int pfifo_fast_enqueue(struct sk_buff *skb, struct Qdisc *qdisc,
|
||||
- struct sk_buff **to_free)
|
||||
-{
|
||||
- int band = prio2band[skb->priority & TC_PRIO_MAX];
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
|
||||
- struct skb_array *q = band2list(priv, band);
|
||||
- unsigned int pkt_len = qdisc_pkt_len(skb);
|
||||
- int err;
|
||||
-
|
||||
- err = skb_array_produce(q, skb);
|
||||
-
|
||||
- if (unlikely(err)) {
|
||||
- if (qdisc_is_percpu_stats(qdisc))
|
||||
- return qdisc_drop_cpu(skb, qdisc, to_free);
|
||||
- else
|
||||
- return qdisc_drop(skb, qdisc, to_free);
|
||||
- }
|
||||
-
|
||||
- qdisc_update_stats_at_enqueue(qdisc, pkt_len);
|
||||
- return NET_XMIT_SUCCESS;
|
||||
-}
|
||||
-
|
||||
-static struct sk_buff *pfifo_fast_dequeue(struct Qdisc *qdisc)
|
||||
-{
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
|
||||
- struct sk_buff *skb = NULL;
|
||||
- int band;
|
||||
-
|
||||
- for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) {
|
||||
- struct skb_array *q = band2list(priv, band);
|
||||
-
|
||||
- if (__skb_array_empty(q))
|
||||
- continue;
|
||||
-
|
||||
- skb = __skb_array_consume(q);
|
||||
- }
|
||||
- if (likely(skb)) {
|
||||
- qdisc_update_stats_at_dequeue(qdisc, skb);
|
||||
- } else {
|
||||
- WRITE_ONCE(qdisc->empty, true);
|
||||
- }
|
||||
-
|
||||
- return skb;
|
||||
-}
|
||||
-
|
||||
-static struct sk_buff *pfifo_fast_peek(struct Qdisc *qdisc)
|
||||
-{
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
|
||||
- struct sk_buff *skb = NULL;
|
||||
- int band;
|
||||
-
|
||||
- for (band = 0; band < PFIFO_FAST_BANDS && !skb; band++) {
|
||||
- struct skb_array *q = band2list(priv, band);
|
||||
-
|
||||
- skb = __skb_array_peek(q);
|
||||
- }
|
||||
-
|
||||
- return skb;
|
||||
-}
|
||||
-
|
||||
-static void pfifo_fast_reset(struct Qdisc *qdisc)
|
||||
-{
|
||||
- int i, band;
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
|
||||
-
|
||||
- for (band = 0; band < PFIFO_FAST_BANDS; band++) {
|
||||
- struct skb_array *q = band2list(priv, band);
|
||||
- struct sk_buff *skb;
|
||||
-
|
||||
- /* NULL ring is possible if destroy path is due to a failed
|
||||
- * skb_array_init() in pfifo_fast_init() case.
|
||||
- */
|
||||
- if (!q->ring.queue)
|
||||
- continue;
|
||||
-
|
||||
- while ((skb = __skb_array_consume(q)) != NULL)
|
||||
- kfree_skb(skb);
|
||||
- }
|
||||
-
|
||||
- if (qdisc_is_percpu_stats(qdisc)) {
|
||||
- for_each_possible_cpu(i) {
|
||||
- struct gnet_stats_queue *q;
|
||||
-
|
||||
- q = per_cpu_ptr(qdisc->cpu_qstats, i);
|
||||
- q->backlog = 0;
|
||||
- q->qlen = 0;
|
||||
- }
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static int pfifo_fast_dump(struct Qdisc *qdisc, struct sk_buff *skb)
|
||||
-{
|
||||
- struct tc_prio_qopt opt = { .bands = PFIFO_FAST_BANDS };
|
||||
-
|
||||
- memcpy(&opt.priomap, prio2band, TC_PRIO_MAX + 1);
|
||||
- if (nla_put(skb, TCA_OPTIONS, sizeof(opt), &opt))
|
||||
- goto nla_put_failure;
|
||||
- return skb->len;
|
||||
-
|
||||
-nla_put_failure:
|
||||
- return -1;
|
||||
-}
|
||||
-
|
||||
-static int pfifo_fast_init(struct Qdisc *qdisc, struct nlattr *opt,
|
||||
- struct netlink_ext_ack *extack)
|
||||
-{
|
||||
- unsigned int qlen = qdisc_dev(qdisc)->tx_queue_len;
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(qdisc);
|
||||
- int prio;
|
||||
-
|
||||
- /* guard against zero length rings */
|
||||
- if (!qlen)
|
||||
- return -EINVAL;
|
||||
-
|
||||
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
|
||||
- struct skb_array *q = band2list(priv, prio);
|
||||
- int err;
|
||||
-
|
||||
- err = skb_array_init(q, qlen, GFP_KERNEL);
|
||||
- if (err)
|
||||
- return -ENOMEM;
|
||||
- }
|
||||
-
|
||||
- /* Can by-pass the queue discipline */
|
||||
- qdisc->flags |= TCQ_F_CAN_BYPASS;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
-static void pfifo_fast_destroy(struct Qdisc *sch)
|
||||
-{
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(sch);
|
||||
- int prio;
|
||||
-
|
||||
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
|
||||
- struct skb_array *q = band2list(priv, prio);
|
||||
-
|
||||
- /* NULL ring is possible if destroy path is due to a failed
|
||||
- * skb_array_init() in pfifo_fast_init() case.
|
||||
- */
|
||||
- if (!q->ring.queue)
|
||||
- continue;
|
||||
- /* Destroy ring but no need to kfree_skb because a call to
|
||||
- * pfifo_fast_reset() has already done that work.
|
||||
- */
|
||||
- ptr_ring_cleanup(&q->ring, NULL);
|
||||
- }
|
||||
-}
|
||||
-
|
||||
-static int pfifo_fast_change_tx_queue_len(struct Qdisc *sch,
|
||||
- unsigned int new_len)
|
||||
-{
|
||||
- struct pfifo_fast_priv *priv = qdisc_priv(sch);
|
||||
- struct skb_array *bands[PFIFO_FAST_BANDS];
|
||||
- int prio;
|
||||
-
|
||||
- for (prio = 0; prio < PFIFO_FAST_BANDS; prio++) {
|
||||
- struct skb_array *q = band2list(priv, prio);
|
||||
-
|
||||
- bands[prio] = q;
|
||||
- }
|
||||
-
|
||||
- return skb_array_resize_multiple(bands, PFIFO_FAST_BANDS, new_len,
|
||||
- GFP_KERNEL);
|
||||
-}
|
||||
-
|
||||
-struct Qdisc_ops pfifo_fast_ops __read_mostly = {
|
||||
- .id = "pfifo_fast",
|
||||
- .priv_size = sizeof(struct pfifo_fast_priv),
|
||||
- .enqueue = pfifo_fast_enqueue,
|
||||
- .dequeue = pfifo_fast_dequeue,
|
||||
- .peek = pfifo_fast_peek,
|
||||
- .init = pfifo_fast_init,
|
||||
- .destroy = pfifo_fast_destroy,
|
||||
- .reset = pfifo_fast_reset,
|
||||
- .dump = pfifo_fast_dump,
|
||||
- .change_tx_queue_len = pfifo_fast_change_tx_queue_len,
|
||||
- .owner = THIS_MODULE,
|
||||
- .static_flags = TCQ_F_NOLOCK | TCQ_F_CPUSTATS,
|
||||
-};
|
||||
-EXPORT_SYMBOL(pfifo_fast_ops);
|
||||
-
|
||||
struct Qdisc *qdisc_alloc(struct netdev_queue *dev_queue,
|
||||
const struct Qdisc_ops *ops,
|
||||
struct netlink_ext_ack *extack)
|
||||
140
target/linux/generic/hack-5.4/700-swconfig_switch_drivers.patch
Normal file
140
target/linux/generic/hack-5.4/700-swconfig_switch_drivers.patch
Normal file
@ -0,0 +1,140 @@
|
||||
From 36e516290611e613aa92996cb4339561452695b4 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:24:23 +0200
|
||||
Subject: net: swconfig: adds openwrt switch layer
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/net/phy/Kconfig | 83 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
drivers/net/phy/Makefile | 15 +++++++++
|
||||
include/uapi/linux/Kbuild | 1 +
|
||||
3 files changed, 99 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/Kconfig
|
||||
+++ b/drivers/net/phy/Kconfig
|
||||
@@ -249,6 +249,89 @@ config LED_TRIGGER_PHY
|
||||
for any speed known to the PHY.
|
||||
|
||||
|
||||
+comment "Switch configuration API + drivers"
|
||||
+
|
||||
+config SWCONFIG
|
||||
+ tristate "Switch configuration API"
|
||||
+ ---help---
|
||||
+ Switch configuration API using netlink. This allows
|
||||
+ you to configure the VLAN features of certain switches.
|
||||
+
|
||||
+config SWCONFIG_LEDS
|
||||
+ bool "Switch LED trigger support"
|
||||
+ depends on (SWCONFIG && LEDS_TRIGGERS)
|
||||
+
|
||||
+config ADM6996_PHY
|
||||
+ tristate "Driver for ADM6996 switches"
|
||||
+ select SWCONFIG
|
||||
+ ---help---
|
||||
+ Currently supports the ADM6996FC and ADM6996M switches.
|
||||
+ Support for FC is very limited.
|
||||
+
|
||||
+config AR8216_PHY
|
||||
+ tristate "Driver for Atheros AR8216 switches"
|
||||
+ select ETHERNET_PACKET_MANGLE
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config AR8216_PHY_LEDS
|
||||
+ bool "Atheros AR8216 switch LED support"
|
||||
+ depends on (AR8216_PHY && LEDS_CLASS)
|
||||
+
|
||||
+source "drivers/net/phy/b53/Kconfig"
|
||||
+
|
||||
+config IP17XX_PHY
|
||||
+ tristate "Driver for IC+ IP17xx switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config MVSWITCH_PHY
|
||||
+ tristate "Driver for Marvell 88E6060 switches"
|
||||
+ select ETHERNET_PACKET_MANGLE
|
||||
+
|
||||
+config MVSW61XX_PHY
|
||||
+ tristate "Driver for Marvell 88E6171/6172 switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config PSB6970_PHY
|
||||
+ tristate "Lantiq XWAY Tantos (PSB6970) Ethernet switch"
|
||||
+ select SWCONFIG
|
||||
+ select ETHERNET_PACKET_MANGLE
|
||||
+
|
||||
+config RTL8306_PHY
|
||||
+ tristate "Driver for Realtek RTL8306S switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8366_SMI
|
||||
+ tristate "Driver for the RTL8366 SMI interface"
|
||||
+ depends on GPIOLIB
|
||||
+ ---help---
|
||||
+ This module implements the SMI interface protocol which is used
|
||||
+ by some RTL8366 ethernet switch devices via the generic GPIO API.
|
||||
+
|
||||
+if RTL8366_SMI
|
||||
+
|
||||
+config RTL8366_SMI_DEBUG_FS
|
||||
+ bool "RTL8366 SMI interface debugfs support"
|
||||
+ depends on DEBUG_FS
|
||||
+ default n
|
||||
+
|
||||
+config RTL8366S_PHY
|
||||
+ tristate "Driver for the Realtek RTL8366S switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8366RB_PHY
|
||||
+ tristate "Driver for the Realtek RTL8366RB switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8367_PHY
|
||||
+ tristate "Driver for the Realtek RTL8367R/M switches"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+config RTL8367B_PHY
|
||||
+ tristate "Driver fot the Realtek RTL8367R-VB switch"
|
||||
+ select SWCONFIG
|
||||
+
|
||||
+endif # RTL8366_SMI
|
||||
+
|
||||
comment "MII PHY device drivers"
|
||||
|
||||
config SFP
|
||||
--- a/drivers/net/phy/Makefile
|
||||
+++ b/drivers/net/phy/Makefile
|
||||
@@ -22,6 +22,21 @@ libphy-$(CONFIG_LED_TRIGGER_PHY) += phy_
|
||||
obj-$(CONFIG_PHYLINK) += phylink.o
|
||||
obj-$(CONFIG_PHYLIB) += libphy.o
|
||||
|
||||
+obj-$(CONFIG_SWCONFIG) += swconfig.o
|
||||
+obj-$(CONFIG_ADM6996_PHY) += adm6996.o
|
||||
+obj-$(CONFIG_AR8216_PHY) += ar8216.o ar8327.o
|
||||
+obj-$(CONFIG_SWCONFIG_B53) += b53/
|
||||
+obj-$(CONFIG_IP17XX_PHY) += ip17xx.o
|
||||
+obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o
|
||||
+obj-$(CONFIG_MVSW61XX_PHY) += mvsw61xx.o
|
||||
+obj-$(CONFIG_PSB6970_PHY) += psb6970.o
|
||||
+obj-$(CONFIG_RTL8306_PHY) += rtl8306.o
|
||||
+obj-$(CONFIG_RTL8366_SMI) += rtl8366_smi.o
|
||||
+obj-$(CONFIG_RTL8366S_PHY) += rtl8366s.o
|
||||
+obj-$(CONFIG_RTL8366RB_PHY) += rtl8366rb.o
|
||||
+obj-$(CONFIG_RTL8367_PHY) += rtl8367.o
|
||||
+obj-$(CONFIG_RTL8367B_PHY) += rtl8367b.o
|
||||
+
|
||||
obj-$(CONFIG_MDIO_ASPEED) += mdio-aspeed.o
|
||||
obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
|
||||
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
|
||||
--- a/include/linux/platform_data/b53.h
|
||||
+++ b/include/linux/platform_data/b53.h
|
||||
@@ -29,6 +29,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,27 @@
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -524,6 +524,12 @@ struct phy_driver {
|
||||
/* Determines the negotiated speed and duplex */
|
||||
int (*read_status)(struct phy_device *phydev);
|
||||
|
||||
+ /*
|
||||
+ * Update the value in phydev->link to reflect the
|
||||
+ * current link value
|
||||
+ */
|
||||
+ int (*update_link)(struct phy_device *phydev);
|
||||
+
|
||||
/* Clears any pending interrupts */
|
||||
int (*ack_interrupt)(struct phy_device *phydev);
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1827,6 +1827,9 @@ int genphy_update_link(struct phy_device
|
||||
if (bmcr & BMCR_ANRESTART)
|
||||
goto done;
|
||||
|
||||
+ if (phydev->drv && phydev->drv->update_link)
|
||||
+ return phydev->drv->update_link(phydev);
|
||||
+
|
||||
/* The link state is latched low so that momentary link
|
||||
* drops can be detected. Do not double-read the status
|
||||
* in polling mode to detect such short link drops.
|
||||
176
target/linux/generic/hack-5.4/721-phy_packets.patch
Normal file
176
target/linux/generic/hack-5.4/721-phy_packets.patch
Normal file
@ -0,0 +1,176 @@
|
||||
From ffe387740bbe88dd88bbe04d6375902708003d6e Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 17:25:00 +0200
|
||||
Subject: net: add packet mangeling patch
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/netdevice.h | 11 +++++++++++
|
||||
include/linux/skbuff.h | 14 ++++----------
|
||||
net/Kconfig | 6 ++++++
|
||||
net/core/dev.c | 18 ++++++++++++++----
|
||||
net/core/skbuff.c | 17 +++++++++++++++++
|
||||
net/ethernet/eth.c | 6 ++++++
|
||||
6 files changed, 58 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/include/linux/netdevice.h
|
||||
+++ b/include/linux/netdevice.h
|
||||
@@ -1546,6 +1546,7 @@ enum netdev_priv_flags {
|
||||
IFF_FAILOVER_SLAVE = 1<<28,
|
||||
IFF_L3MDEV_RX_HANDLER = 1<<29,
|
||||
IFF_LIVE_RENAME_OK = 1<<30,
|
||||
+ IFF_NO_IP_ALIGN = 1<<31,
|
||||
};
|
||||
|
||||
#define IFF_802_1Q_VLAN IFF_802_1Q_VLAN
|
||||
@@ -1578,6 +1579,7 @@ enum netdev_priv_flags {
|
||||
#define IFF_FAILOVER_SLAVE IFF_FAILOVER_SLAVE
|
||||
#define IFF_L3MDEV_RX_HANDLER IFF_L3MDEV_RX_HANDLER
|
||||
#define IFF_LIVE_RENAME_OK IFF_LIVE_RENAME_OK
|
||||
+#define IFF_NO_IP_ALIGN IFF_NO_IP_ALIGN
|
||||
|
||||
/**
|
||||
* struct net_device - The DEVICE structure.
|
||||
@@ -1879,6 +1881,11 @@ struct net_device {
|
||||
const struct tlsdev_ops *tlsdev_ops;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ void (*eth_mangle_rx)(struct net_device *dev, struct sk_buff *skb);
|
||||
+ struct sk_buff *(*eth_mangle_tx)(struct net_device *dev, struct sk_buff *skb);
|
||||
+#endif
|
||||
+
|
||||
const struct header_ops *header_ops;
|
||||
|
||||
unsigned int flags;
|
||||
@@ -1961,6 +1968,10 @@ struct net_device {
|
||||
struct mpls_dev __rcu *mpls_ptr;
|
||||
#endif
|
||||
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ void *phy_ptr; /* PHY device specific data */
|
||||
+#endif
|
||||
+
|
||||
/*
|
||||
* Cache lines mostly used on receive path (including eth_type_trans())
|
||||
*/
|
||||
--- a/include/linux/skbuff.h
|
||||
+++ b/include/linux/skbuff.h
|
||||
@@ -2667,6 +2667,10 @@ static inline int pskb_trim(struct sk_bu
|
||||
return (len < skb->len) ? __pskb_trim(skb, len) : 0;
|
||||
}
|
||||
|
||||
+extern struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp);
|
||||
+
|
||||
+
|
||||
/**
|
||||
* pskb_trim_unique - remove end from a paged unique (not cloned) buffer
|
||||
* @skb: buffer to alter
|
||||
@@ -2798,16 +2802,6 @@ static inline struct sk_buff *dev_alloc_
|
||||
}
|
||||
|
||||
|
||||
-static inline struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
- unsigned int length, gfp_t gfp)
|
||||
-{
|
||||
- struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
|
||||
-
|
||||
- if (NET_IP_ALIGN && skb)
|
||||
- skb_reserve(skb, NET_IP_ALIGN);
|
||||
- return skb;
|
||||
-}
|
||||
-
|
||||
static inline struct sk_buff *netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
unsigned int length)
|
||||
{
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -26,6 +26,12 @@ menuconfig NET
|
||||
|
||||
if NET
|
||||
|
||||
+config ETHERNET_PACKET_MANGLE
|
||||
+ bool
|
||||
+ help
|
||||
+ This option can be selected by phy drivers that need to mangle
|
||||
+ packets going in or out of an ethernet device.
|
||||
+
|
||||
config WANT_COMPAT_NETLINK_MESSAGES
|
||||
bool
|
||||
help
|
||||
--- a/net/core/dev.c
|
||||
+++ b/net/core/dev.c
|
||||
@@ -3195,10 +3195,20 @@ static int xmit_one(struct sk_buff *skb,
|
||||
if (dev_nit_active(dev))
|
||||
dev_queue_xmit_nit(skb, dev);
|
||||
|
||||
- len = skb->len;
|
||||
- trace_net_dev_start_xmit(skb, dev);
|
||||
- rc = netdev_start_xmit(skb, dev, txq, more);
|
||||
- trace_net_dev_xmit(skb, rc, dev, len);
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (!dev->eth_mangle_tx ||
|
||||
+ (skb = dev->eth_mangle_tx(dev, skb)) != NULL)
|
||||
+#else
|
||||
+ if (1)
|
||||
+#endif
|
||||
+ {
|
||||
+ len = skb->len;
|
||||
+ trace_net_dev_start_xmit(skb, dev);
|
||||
+ rc = netdev_start_xmit(skb, dev, txq, more);
|
||||
+ trace_net_dev_xmit(skb, rc, dev, len);
|
||||
+ } else {
|
||||
+ rc = NETDEV_TX_OK;
|
||||
+ }
|
||||
|
||||
return rc;
|
||||
}
|
||||
--- a/net/core/skbuff.c
|
||||
+++ b/net/core/skbuff.c
|
||||
@@ -60,6 +60,7 @@
|
||||
#include <linux/prefetch.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/mpls.h>
|
||||
+#include <linux/if.h>
|
||||
|
||||
#include <net/protocol.h>
|
||||
#include <net/dst.h>
|
||||
@@ -540,6 +541,22 @@ skb_fail:
|
||||
}
|
||||
EXPORT_SYMBOL(__napi_alloc_skb);
|
||||
|
||||
+struct sk_buff *__netdev_alloc_skb_ip_align(struct net_device *dev,
|
||||
+ unsigned int length, gfp_t gfp)
|
||||
+{
|
||||
+ struct sk_buff *skb = __netdev_alloc_skb(dev, length + NET_IP_ALIGN, gfp);
|
||||
+
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (dev && (dev->priv_flags & IFF_NO_IP_ALIGN))
|
||||
+ return skb;
|
||||
+#endif
|
||||
+
|
||||
+ if (NET_IP_ALIGN && skb)
|
||||
+ skb_reserve(skb, NET_IP_ALIGN);
|
||||
+ return skb;
|
||||
+}
|
||||
+EXPORT_SYMBOL(__netdev_alloc_skb_ip_align);
|
||||
+
|
||||
void skb_add_rx_frag(struct sk_buff *skb, int i, struct page *page, int off,
|
||||
int size, unsigned int truesize)
|
||||
{
|
||||
--- a/net/ethernet/eth.c
|
||||
+++ b/net/ethernet/eth.c
|
||||
@@ -171,6 +171,12 @@ __be16 eth_type_trans(struct sk_buff *sk
|
||||
const struct ethhdr *eth;
|
||||
|
||||
skb->dev = dev;
|
||||
+
|
||||
+#ifdef CONFIG_ETHERNET_PACKET_MANGLE
|
||||
+ if (dev->eth_mangle_rx)
|
||||
+ dev->eth_mangle_rx(dev, skb);
|
||||
+#endif
|
||||
+
|
||||
skb_reset_mac_header(skb);
|
||||
|
||||
eth = (struct ethhdr *)skb->data;
|
||||
@ -0,0 +1,98 @@
|
||||
From 3cb240533ab787899dc7f17aa7d6c5b4810e2e58 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Fri, 7 Jul 2017 17:26:01 +0200
|
||||
Subject: bcm53xx: bgmac: use srab switch driver
|
||||
|
||||
use the srab switch driver on these SoCs.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
drivers/net/ethernet/broadcom/bgmac-bcma.c | 1 +
|
||||
drivers/net/ethernet/broadcom/bgmac.c | 24 ++++++++++++++++++++++++
|
||||
drivers/net/ethernet/broadcom/bgmac.h | 4 ++++
|
||||
3 files changed, 29 insertions(+)
|
||||
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||
@@ -268,6 +268,7 @@ static int bgmac_probe(struct bcma_devic
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_NO_RESET;
|
||||
bgmac->feature_flags |= BGMAC_FEAT_FORCE_SPEED_2500;
|
||||
+ bgmac->feature_flags |= BGMAC_FEAT_SRAB;
|
||||
break;
|
||||
default:
|
||||
bgmac->feature_flags |= BGMAC_FEAT_CLKCTLST;
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <linux/bcma/bcma.h>
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
+#include <linux/platform_data/b53.h>
|
||||
#include <linux/bcm47xx_nvram.h>
|
||||
#include <linux/phy.h>
|
||||
#include <linux/phy_fixed.h>
|
||||
@@ -1407,6 +1408,17 @@ static const struct ethtool_ops bgmac_et
|
||||
.set_link_ksettings = phy_ethtool_set_link_ksettings,
|
||||
};
|
||||
|
||||
+static struct b53_platform_data bgmac_b53_pdata = {
|
||||
+};
|
||||
+
|
||||
+static struct platform_device bgmac_b53_dev = {
|
||||
+ .name = "b53-srab-switch",
|
||||
+ .id = -1,
|
||||
+ .dev = {
|
||||
+ .platform_data = &bgmac_b53_pdata,
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
/**************************************************
|
||||
* MII
|
||||
**************************************************/
|
||||
@@ -1538,6 +1550,14 @@ int bgmac_enet_probe(struct bgmac *bgmac
|
||||
net_dev->hw_features = net_dev->features;
|
||||
net_dev->vlan_features = net_dev->features;
|
||||
|
||||
+ if ((bgmac->feature_flags & BGMAC_FEAT_SRAB) && !bgmac_b53_pdata.regs) {
|
||||
+ bgmac_b53_pdata.regs = ioremap_nocache(0x18007000, 0x1000);
|
||||
+
|
||||
+ err = platform_device_register(&bgmac_b53_dev);
|
||||
+ if (!err)
|
||||
+ bgmac->b53_device = &bgmac_b53_dev;
|
||||
+ }
|
||||
+
|
||||
err = register_netdev(bgmac->net_dev);
|
||||
if (err) {
|
||||
dev_err(bgmac->dev, "Cannot register net device\n");
|
||||
@@ -1560,6 +1580,10 @@ EXPORT_SYMBOL_GPL(bgmac_enet_probe);
|
||||
|
||||
void bgmac_enet_remove(struct bgmac *bgmac)
|
||||
{
|
||||
+ if (bgmac->b53_device)
|
||||
+ platform_device_unregister(&bgmac_b53_dev);
|
||||
+ bgmac->b53_device = NULL;
|
||||
+
|
||||
unregister_netdev(bgmac->net_dev);
|
||||
phy_disconnect(bgmac->net_dev->phydev);
|
||||
netif_napi_del(&bgmac->napi);
|
||||
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||
@@ -427,6 +427,7 @@
|
||||
#define BGMAC_FEAT_CC4_IF_SW_TYPE_RGMII BIT(18)
|
||||
#define BGMAC_FEAT_CC7_IF_TYPE_RGMII BIT(19)
|
||||
#define BGMAC_FEAT_IDM_MASK BIT(20)
|
||||
+#define BGMAC_FEAT_SRAB BIT(21)
|
||||
|
||||
struct bgmac_slot_info {
|
||||
union {
|
||||
@@ -532,6 +533,9 @@ struct bgmac {
|
||||
void (*cmn_maskset32)(struct bgmac *bgmac, u16 offset, u32 mask,
|
||||
u32 set);
|
||||
int (*phy_connect)(struct bgmac *bgmac);
|
||||
+
|
||||
+ /* platform device for associated switch */
|
||||
+ struct platform_device *b53_device;
|
||||
};
|
||||
|
||||
struct bgmac *bgmac_alloc(struct device *dev);
|
||||
145
target/linux/generic/hack-5.4/901-debloat_sock_diag.patch
Normal file
145
target/linux/generic/hack-5.4/901-debloat_sock_diag.patch
Normal file
@ -0,0 +1,145 @@
|
||||
From 3b6115d6b57a263bdc8c9b1df273bd4a7955eead Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 8 Jul 2017 08:16:31 +0200
|
||||
Subject: debloat: add some debloat patches, strip down procfs and make O_DIRECT support optional, saves ~15K after lzma on MIPS
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
net/Kconfig | 3 +++
|
||||
net/core/Makefile | 3 ++-
|
||||
net/core/sock.c | 2 ++
|
||||
net/ipv4/Kconfig | 1 +
|
||||
net/netlink/Kconfig | 1 +
|
||||
net/packet/Kconfig | 1 +
|
||||
net/unix/Kconfig | 1 +
|
||||
7 files changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/net/Kconfig
|
||||
+++ b/net/Kconfig
|
||||
@@ -103,6 +103,9 @@ source "net/netlabel/Kconfig"
|
||||
|
||||
endif # if INET
|
||||
|
||||
+config SOCK_DIAG
|
||||
+ bool
|
||||
+
|
||||
config NETWORK_SECMARK
|
||||
bool "Security Marking"
|
||||
help
|
||||
--- a/net/core/Makefile
|
||||
+++ b/net/core/Makefile
|
||||
@@ -10,9 +10,10 @@ obj-$(CONFIG_SYSCTL) += sysctl_net_core.
|
||||
|
||||
obj-y += dev.o ethtool.o dev_addr_lists.o dst.o netevent.o \
|
||||
neighbour.o rtnetlink.o utils.o link_watch.o filter.o \
|
||||
- sock_diag.o dev_ioctl.o tso.o sock_reuseport.o \
|
||||
+ dev_ioctl.o tso.o sock_reuseport.o \
|
||||
fib_notifier.o xdp.o flow_offload.o
|
||||
|
||||
+obj-$(CONFIG_SOCK_DIAG) += sock_diag.o
|
||||
obj-y += net-sysfs.o
|
||||
obj-$(CONFIG_PAGE_POOL) += page_pool.o
|
||||
obj-$(CONFIG_PROC_FS) += net-procfs.o
|
||||
--- a/net/core/sock.c
|
||||
+++ b/net/core/sock.c
|
||||
@@ -140,6 +140,7 @@
|
||||
|
||||
static DEFINE_MUTEX(proto_list_mutex);
|
||||
static LIST_HEAD(proto_list);
|
||||
+static atomic64_t cookie_gen;
|
||||
|
||||
static void sock_inuse_add(struct net *net, int val);
|
||||
|
||||
@@ -539,6 +540,18 @@ discard_and_relse:
|
||||
}
|
||||
EXPORT_SYMBOL(__sk_receive_skb);
|
||||
|
||||
+u64 sock_gen_cookie(struct sock *sk)
|
||||
+{
|
||||
+ while (1) {
|
||||
+ u64 res = atomic64_read(&sk->sk_cookie);
|
||||
+
|
||||
+ if (res)
|
||||
+ return res;
|
||||
+ res = atomic64_inc_return(&cookie_gen);
|
||||
+ atomic64_cmpxchg(&sk->sk_cookie, 0, res);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
struct dst_entry *__sk_dst_check(struct sock *sk, u32 cookie)
|
||||
{
|
||||
struct dst_entry *dst = __sk_dst_get(sk);
|
||||
@@ -1746,9 +1759,11 @@ static void __sk_free(struct sock *sk)
|
||||
if (likely(sk->sk_net_refcnt))
|
||||
sock_inuse_add(sock_net(sk), -1);
|
||||
|
||||
+#ifdef CONFIG_SOCK_DIAG
|
||||
if (unlikely(sk->sk_net_refcnt && sock_diag_has_destroy_listeners(sk)))
|
||||
sock_diag_broadcast_destroy(sk);
|
||||
else
|
||||
+#endif
|
||||
sk_destruct(sk);
|
||||
}
|
||||
|
||||
--- a/net/core/sock_diag.c
|
||||
+++ b/net/core/sock_diag.c
|
||||
@@ -19,19 +19,6 @@ static const struct sock_diag_handler *s
|
||||
static int (*inet_rcv_compat)(struct sk_buff *skb, struct nlmsghdr *nlh);
|
||||
static DEFINE_MUTEX(sock_diag_table_mutex);
|
||||
static struct workqueue_struct *broadcast_wq;
|
||||
-static atomic64_t cookie_gen;
|
||||
-
|
||||
-u64 sock_gen_cookie(struct sock *sk)
|
||||
-{
|
||||
- while (1) {
|
||||
- u64 res = atomic64_read(&sk->sk_cookie);
|
||||
-
|
||||
- if (res)
|
||||
- return res;
|
||||
- res = atomic64_inc_return(&cookie_gen);
|
||||
- atomic64_cmpxchg(&sk->sk_cookie, 0, res);
|
||||
- }
|
||||
-}
|
||||
|
||||
int sock_diag_check_cookie(struct sock *sk, const __u32 *cookie)
|
||||
{
|
||||
--- a/net/ipv4/Kconfig
|
||||
+++ b/net/ipv4/Kconfig
|
||||
@@ -400,6 +400,7 @@ config INET_TUNNEL
|
||||
|
||||
config INET_DIAG
|
||||
tristate "INET: socket monitoring interface"
|
||||
+ select SOCK_DIAG
|
||||
default y
|
||||
---help---
|
||||
Support for INET (TCP, DCCP, etc) socket monitoring interface used by
|
||||
--- a/net/netlink/Kconfig
|
||||
+++ b/net/netlink/Kconfig
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
config NETLINK_DIAG
|
||||
tristate "NETLINK: socket monitoring interface"
|
||||
+ select SOCK_DIAG
|
||||
default n
|
||||
---help---
|
||||
Support for NETLINK socket monitoring interface used by the ss tool.
|
||||
--- a/net/packet/Kconfig
|
||||
+++ b/net/packet/Kconfig
|
||||
@@ -19,6 +19,7 @@ config PACKET
|
||||
config PACKET_DIAG
|
||||
tristate "Packet: sockets monitoring interface"
|
||||
depends on PACKET
|
||||
+ select SOCK_DIAG
|
||||
default n
|
||||
---help---
|
||||
Support for PF_PACKET sockets monitoring interface used by the ss tool.
|
||||
--- a/net/unix/Kconfig
|
||||
+++ b/net/unix/Kconfig
|
||||
@@ -28,6 +28,7 @@ config UNIX_SCM
|
||||
config UNIX_DIAG
|
||||
tristate "UNIX: socket monitoring interface"
|
||||
depends on UNIX
|
||||
+ select SOCK_DIAG
|
||||
default n
|
||||
---help---
|
||||
Support for UNIX socket monitoring interface used by the ss tool.
|
||||
408
target/linux/generic/hack-5.4/902-debloat_proc.patch
Normal file
408
target/linux/generic/hack-5.4/902-debloat_proc.patch
Normal file
@ -0,0 +1,408 @@
|
||||
From 9e3f1d0805b2d919904dd9a4ff0d956314cc3cba Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 8 Jul 2017 08:20:09 +0200
|
||||
Subject: debloat: procfs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
fs/locks.c | 2 ++
|
||||
fs/proc/Kconfig | 5 +++++
|
||||
fs/proc/consoles.c | 3 +++
|
||||
fs/proc/proc_tty.c | 11 ++++++++++-
|
||||
include/net/snmp.h | 18 +++++++++++++++++-
|
||||
ipc/msg.c | 3 +++
|
||||
ipc/sem.c | 2 ++
|
||||
ipc/shm.c | 2 ++
|
||||
ipc/util.c | 3 +++
|
||||
kernel/exec_domain.c | 2 ++
|
||||
kernel/irq/proc.c | 9 +++++++++
|
||||
kernel/time/timer_list.c | 2 ++
|
||||
mm/vmalloc.c | 2 ++
|
||||
mm/vmstat.c | 8 +++++---
|
||||
net/8021q/vlanproc.c | 6 ++++++
|
||||
net/core/net-procfs.c | 18 ++++++++++++------
|
||||
net/core/sock.c | 2 ++
|
||||
net/ipv4/fib_trie.c | 18 ++++++++++++------
|
||||
net/ipv4/proc.c | 3 +++
|
||||
net/ipv4/route.c | 3 +++
|
||||
20 files changed, 105 insertions(+), 17 deletions(-)
|
||||
|
||||
--- a/fs/locks.c
|
||||
+++ b/fs/locks.c
|
||||
@@ -2989,6 +2989,8 @@ static const struct seq_operations locks
|
||||
|
||||
static int __init proc_locks_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
proc_create_seq_private("locks", 0, NULL, &locks_seq_operations,
|
||||
sizeof(struct locks_iterator), NULL);
|
||||
return 0;
|
||||
--- a/fs/proc/Kconfig
|
||||
+++ b/fs/proc/Kconfig
|
||||
@@ -100,6 +100,11 @@ config PROC_CHILDREN
|
||||
Say Y if you are running any user-space software which takes benefit from
|
||||
this interface. For example, rkt is such a piece of software.
|
||||
|
||||
+config PROC_STRIPPED
|
||||
+ default n
|
||||
+ depends on EXPERT
|
||||
+ bool "Strip non-essential /proc functionality to reduce code size"
|
||||
+
|
||||
config PROC_PID_ARCH_STATUS
|
||||
def_bool n
|
||||
depends on PROC_FS
|
||||
--- a/fs/proc/consoles.c
|
||||
+++ b/fs/proc/consoles.c
|
||||
@@ -92,6 +92,9 @@ static const struct seq_operations conso
|
||||
|
||||
static int __init proc_consoles_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
proc_create_seq("consoles", 0, NULL, &consoles_op);
|
||||
return 0;
|
||||
}
|
||||
--- a/fs/proc/proc_tty.c
|
||||
+++ b/fs/proc/proc_tty.c
|
||||
@@ -133,7 +133,10 @@ static const struct seq_operations tty_d
|
||||
void proc_tty_register_driver(struct tty_driver *driver)
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
-
|
||||
+
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (!driver->driver_name || driver->proc_entry ||
|
||||
!driver->ops->proc_show)
|
||||
return;
|
||||
@@ -150,6 +153,9 @@ void proc_tty_unregister_driver(struct t
|
||||
{
|
||||
struct proc_dir_entry *ent;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
ent = driver->proc_entry;
|
||||
if (!ent)
|
||||
return;
|
||||
@@ -164,6 +170,9 @@ void proc_tty_unregister_driver(struct t
|
||||
*/
|
||||
void __init proc_tty_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (!proc_mkdir("tty", NULL))
|
||||
return;
|
||||
proc_mkdir("tty/ldisc", NULL); /* Preserved: it's userspace visible */
|
||||
--- a/include/net/snmp.h
|
||||
+++ b/include/net/snmp.h
|
||||
@@ -118,6 +118,21 @@ struct linux_xfrm_mib {
|
||||
#define DECLARE_SNMP_STAT(type, name) \
|
||||
extern __typeof__(type) __percpu *name
|
||||
|
||||
+#ifdef CONFIG_PROC_STRIPPED
|
||||
+#define __SNMP_STATS_DUMMY(mib) \
|
||||
+ do { (void) mib->mibs[0]; } while(0)
|
||||
+
|
||||
+#define __SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_INC_STATS_ATOMIC_LONG(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_INC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_DEC_STATS(mib, field) __SNMP_STATS_DUMMY(mib)
|
||||
+#define __SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_ADD_STATS(mib, field, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+#define __SNMP_UPD_PO_STATS(mib, basefield, addend) __SNMP_STATS_DUMMY(mib)
|
||||
+
|
||||
+#else
|
||||
+
|
||||
#define __SNMP_INC_STATS(mib, field) \
|
||||
__this_cpu_inc(mib->mibs[field])
|
||||
|
||||
@@ -148,8 +163,9 @@ struct linux_xfrm_mib {
|
||||
__this_cpu_add(ptr[basefield##OCTETS], addend); \
|
||||
} while (0)
|
||||
|
||||
+#endif
|
||||
|
||||
-#if BITS_PER_LONG==32
|
||||
+#if (BITS_PER_LONG==32) && !defined(CONFIG_PROC_STRIPPED)
|
||||
|
||||
#define __SNMP_ADD_STATS64(mib, field, addend) \
|
||||
do { \
|
||||
--- a/ipc/msg.c
|
||||
+++ b/ipc/msg.c
|
||||
@@ -1317,6 +1317,9 @@ void __init msg_init(void)
|
||||
{
|
||||
msg_init_ns(&init_ipc_ns);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
ipc_init_proc_interface("sysvipc/msg",
|
||||
" key msqid perms cbytes qnum lspid lrpid uid gid cuid cgid stime rtime ctime\n",
|
||||
IPC_MSG_IDS, sysvipc_msg_proc_show);
|
||||
--- a/ipc/sem.c
|
||||
+++ b/ipc/sem.c
|
||||
@@ -243,6 +243,8 @@ void sem_exit_ns(struct ipc_namespace *n
|
||||
void __init sem_init(void)
|
||||
{
|
||||
sem_init_ns(&init_ipc_ns);
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
ipc_init_proc_interface("sysvipc/sem",
|
||||
" key semid perms nsems uid gid cuid cgid otime ctime\n",
|
||||
IPC_SEM_IDS, sysvipc_sem_proc_show);
|
||||
--- a/ipc/shm.c
|
||||
+++ b/ipc/shm.c
|
||||
@@ -144,6 +144,8 @@ pure_initcall(ipc_ns_init);
|
||||
|
||||
void __init shm_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
ipc_init_proc_interface("sysvipc/shm",
|
||||
#if BITS_PER_LONG <= 32
|
||||
" key shmid perms size cpid lpid nattch uid gid cuid cgid atime dtime ctime rss swap\n",
|
||||
--- a/ipc/util.c
|
||||
+++ b/ipc/util.c
|
||||
@@ -140,6 +140,9 @@ void __init ipc_init_proc_interface(cons
|
||||
struct proc_dir_entry *pde;
|
||||
struct ipc_proc_iface *iface;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
iface = kmalloc(sizeof(*iface), GFP_KERNEL);
|
||||
if (!iface)
|
||||
return;
|
||||
--- a/kernel/exec_domain.c
|
||||
+++ b/kernel/exec_domain.c
|
||||
@@ -29,6 +29,8 @@ static int execdomains_proc_show(struct
|
||||
|
||||
static int __init proc_execdomains_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
proc_create_single("execdomains", 0, NULL, execdomains_proc_show);
|
||||
return 0;
|
||||
}
|
||||
--- a/kernel/irq/proc.c
|
||||
+++ b/kernel/irq/proc.c
|
||||
@@ -341,6 +341,9 @@ void register_irq_proc(unsigned int irq,
|
||||
void __maybe_unused *irqp = (void *)(unsigned long) irq;
|
||||
char name [MAX_NAMELEN];
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
if (!root_irq_dir || (desc->irq_data.chip == &no_irq_chip))
|
||||
return;
|
||||
|
||||
@@ -394,6 +397,9 @@ void unregister_irq_proc(unsigned int ir
|
||||
{
|
||||
char name [MAX_NAMELEN];
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
if (!root_irq_dir || !desc->dir)
|
||||
return;
|
||||
#ifdef CONFIG_SMP
|
||||
@@ -432,6 +438,9 @@ void init_irq_proc(void)
|
||||
unsigned int irq;
|
||||
struct irq_desc *desc;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED) && !IS_ENABLED(CONFIG_SMP))
|
||||
+ return;
|
||||
+
|
||||
/* create /proc/irq */
|
||||
root_irq_dir = proc_mkdir("irq", NULL);
|
||||
if (!root_irq_dir)
|
||||
--- a/kernel/time/timer_list.c
|
||||
+++ b/kernel/time/timer_list.c
|
||||
@@ -370,6 +370,8 @@ static int __init init_timer_list_procfs
|
||||
{
|
||||
struct proc_dir_entry *pe;
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
pe = proc_create_seq_private("timer_list", 0400, NULL, &timer_list_sops,
|
||||
sizeof(struct timer_list_iter), NULL);
|
||||
if (!pe)
|
||||
--- a/mm/vmalloc.c
|
||||
+++ b/mm/vmalloc.c
|
||||
@@ -3552,6 +3552,8 @@ static const struct seq_operations vmall
|
||||
|
||||
static int __init proc_vmalloc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
if (IS_ENABLED(CONFIG_NUMA))
|
||||
proc_create_seq_private("vmallocinfo", 0400, NULL,
|
||||
&vmalloc_op,
|
||||
--- a/mm/vmstat.c
|
||||
+++ b/mm/vmstat.c
|
||||
@@ -1988,10 +1988,12 @@ void __init init_mm_internals(void)
|
||||
start_shepherd_timer();
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
- proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
|
||||
- proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ proc_create_seq("buddyinfo", 0444, NULL, &fragmentation_op);
|
||||
+ proc_create_seq("pagetypeinfo", 0400, NULL, &pagetypeinfo_op);
|
||||
+ proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
|
||||
+ }
|
||||
proc_create_seq("vmstat", 0444, NULL, &vmstat_op);
|
||||
- proc_create_seq("zoneinfo", 0444, NULL, &zoneinfo_op);
|
||||
#endif
|
||||
}
|
||||
|
||||
--- a/net/8021q/vlanproc.c
|
||||
+++ b/net/8021q/vlanproc.c
|
||||
@@ -93,6 +93,9 @@ void vlan_proc_cleanup(struct net *net)
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return;
|
||||
+
|
||||
if (vn->proc_vlan_conf)
|
||||
remove_proc_entry(name_conf, vn->proc_vlan_dir);
|
||||
|
||||
@@ -112,6 +115,9 @@ int __net_init vlan_proc_init(struct net
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
vn->proc_vlan_dir = proc_net_mkdir(net, name_root, net->proc_net);
|
||||
if (!vn->proc_vlan_dir)
|
||||
goto err;
|
||||
--- a/net/core/net-procfs.c
|
||||
+++ b/net/core/net-procfs.c
|
||||
@@ -279,10 +279,12 @@ static int __net_init dev_proc_net_init(
|
||||
if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
|
||||
sizeof(struct seq_net_private)))
|
||||
goto out;
|
||||
- if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_seq("softnet_stat", 0444, net->proc_net,
|
||||
&softnet_seq_ops))
|
||||
goto out_dev;
|
||||
- if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
|
||||
sizeof(struct seq_net_private)))
|
||||
goto out_softnet;
|
||||
|
||||
@@ -292,9 +294,11 @@ static int __net_init dev_proc_net_init(
|
||||
out:
|
||||
return rc;
|
||||
out_ptype:
|
||||
- remove_proc_entry("ptype", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("ptype", net->proc_net);
|
||||
out_softnet:
|
||||
- remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("softnet_stat", net->proc_net);
|
||||
out_dev:
|
||||
remove_proc_entry("dev", net->proc_net);
|
||||
goto out;
|
||||
@@ -304,8 +308,10 @@ static void __net_exit dev_proc_net_exit
|
||||
{
|
||||
wext_proc_exit(net);
|
||||
|
||||
- remove_proc_entry("ptype", net->proc_net);
|
||||
- remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ remove_proc_entry("ptype", net->proc_net);
|
||||
+ remove_proc_entry("softnet_stat", net->proc_net);
|
||||
+ }
|
||||
remove_proc_entry("dev", net->proc_net);
|
||||
}
|
||||
|
||||
--- a/net/core/sock.c
|
||||
+++ b/net/core/sock.c
|
||||
@@ -3606,6 +3606,8 @@ static __net_initdata struct pernet_oper
|
||||
|
||||
static int __init proto_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
return register_pernet_subsys(&proto_net_ops);
|
||||
}
|
||||
|
||||
--- a/net/ipv4/fib_trie.c
|
||||
+++ b/net/ipv4/fib_trie.c
|
||||
@@ -2844,11 +2844,13 @@ static const struct seq_operations fib_r
|
||||
|
||||
int __net_init fib_proc_init(struct net *net)
|
||||
{
|
||||
- if (!proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net("fib_trie", 0444, net->proc_net, &fib_trie_seq_ops,
|
||||
sizeof(struct fib_trie_iter)))
|
||||
goto out1;
|
||||
|
||||
- if (!proc_create_net_single("fib_triestat", 0444, net->proc_net,
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED) &&
|
||||
+ !proc_create_net_single("fib_triestat", 0444, net->proc_net,
|
||||
fib_triestat_seq_show, NULL))
|
||||
goto out2;
|
||||
|
||||
@@ -2859,17 +2861,21 @@ int __net_init fib_proc_init(struct net
|
||||
return 0;
|
||||
|
||||
out3:
|
||||
- remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("fib_triestat", net->proc_net);
|
||||
out2:
|
||||
- remove_proc_entry("fib_trie", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ remove_proc_entry("fib_trie", net->proc_net);
|
||||
out1:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
void __net_exit fib_proc_exit(struct net *net)
|
||||
{
|
||||
- remove_proc_entry("fib_trie", net->proc_net);
|
||||
- remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ if (!IS_ENABLED(CONFIG_PROC_STRIPPED)) {
|
||||
+ remove_proc_entry("fib_trie", net->proc_net);
|
||||
+ remove_proc_entry("fib_triestat", net->proc_net);
|
||||
+ }
|
||||
remove_proc_entry("route", net->proc_net);
|
||||
}
|
||||
|
||||
--- a/net/ipv4/proc.c
|
||||
+++ b/net/ipv4/proc.c
|
||||
@@ -522,5 +522,8 @@ static __net_initdata struct pernet_oper
|
||||
|
||||
int __init ip_misc_proc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
return register_pernet_subsys(&ip_proc_ops);
|
||||
}
|
||||
--- a/net/ipv4/route.c
|
||||
+++ b/net/ipv4/route.c
|
||||
@@ -408,6 +408,9 @@ static struct pernet_operations ip_rt_pr
|
||||
|
||||
static int __init ip_rt_proc_init(void)
|
||||
{
|
||||
+ if (IS_ENABLED(CONFIG_PROC_STRIPPED))
|
||||
+ return 0;
|
||||
+
|
||||
return register_pernet_subsys(&ip_rt_proc_ops);
|
||||
}
|
||||
|
||||
74
target/linux/generic/hack-5.4/904-debloat_dma_buf.patch
Normal file
74
target/linux/generic/hack-5.4/904-debloat_dma_buf.patch
Normal file
@ -0,0 +1,74 @@
|
||||
From e3692cb2fcd5ba1244512a0f43b8118f65f1c375 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 8 Jul 2017 08:20:43 +0200
|
||||
Subject: debloat: dmabuf
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
drivers/base/Kconfig | 2 +-
|
||||
drivers/dma-buf/Makefile | 10 +++++++---
|
||||
drivers/dma-buf/dma-buf.c | 4 +++-
|
||||
kernel/sched/core.c | 1 +
|
||||
4 files changed, 12 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/base/Kconfig
|
||||
+++ b/drivers/base/Kconfig
|
||||
@@ -179,7 +179,7 @@ config SOC_BUS
|
||||
source "drivers/base/regmap/Kconfig"
|
||||
|
||||
config DMA_SHARED_BUFFER
|
||||
- bool
|
||||
+ tristate
|
||||
default n
|
||||
select IRQ_WORK
|
||||
help
|
||||
--- a/drivers/dma-buf/Makefile
|
||||
+++ b/drivers/dma-buf/Makefile
|
||||
@@ -1,9 +1,13 @@
|
||||
# SPDX-License-Identifier: GPL-2.0-only
|
||||
-obj-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
|
||||
- dma-resv.o seqno-fence.o
|
||||
-obj-$(CONFIG_SYNC_FILE) += sync_file.o
|
||||
-obj-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
|
||||
-obj-$(CONFIG_UDMABUF) += udmabuf.o
|
||||
+obj-$(CONFIG_DMA_SHARED_BUFFER) := dma-shared-buffer.o
|
||||
+
|
||||
+dma-buf-objs-y := dma-buf.o dma-fence.o dma-fence-array.o dma-fence-chain.o \
|
||||
+ dma-resv.o seqno-fence.o
|
||||
+dma-buf-objs-$(CONFIG_SYNC_FILE) += sync_file.o
|
||||
+dma-buf-objs-$(CONFIG_SW_SYNC) += sw_sync.o sync_debug.o
|
||||
+dma-buf-objs-$(CONFIG_UDMABUF) += udmabuf.o
|
||||
+
|
||||
+dma-shared-buffer-objs := $(dma-buf-objs-y)
|
||||
|
||||
dmabuf_selftests-y := \
|
||||
selftest.o \
|
||||
--- a/drivers/dma-buf/dma-buf.c
|
||||
+++ b/drivers/dma-buf/dma-buf.c
|
||||
@@ -1298,4 +1298,5 @@ static void __exit dma_buf_deinit(void)
|
||||
dma_buf_uninit_debugfs();
|
||||
kern_unmount(dma_buf_mnt);
|
||||
}
|
||||
-__exitcall(dma_buf_deinit);
|
||||
+module_exit(dma_buf_deinit);
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/kernel/sched/core.c
|
||||
+++ b/kernel/sched/core.c
|
||||
@@ -2673,6 +2673,7 @@ int wake_up_state(struct task_struct *p,
|
||||
{
|
||||
return try_to_wake_up(p, state, 0);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(wake_up_state);
|
||||
|
||||
/*
|
||||
* Perform scheduler related setup for a newly forked process p.
|
||||
--- a/fs/d_path.c
|
||||
+++ b/fs/d_path.c
|
||||
@@ -307,6 +307,7 @@ char *dynamic_dname(struct dentry *dentr
|
||||
buffer += buflen - sz;
|
||||
return memcpy(buffer, temp, sz);
|
||||
}
|
||||
+EXPORT_SYMBOL_GPL(dynamic_dname);
|
||||
|
||||
char *simple_dname(struct dentry *dentry, char *buffer, int buflen)
|
||||
{
|
||||
32
target/linux/generic/hack-5.4/910-kobject_uevent.patch
Normal file
32
target/linux/generic/hack-5.4/910-kobject_uevent.patch
Normal file
@ -0,0 +1,32 @@
|
||||
From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 16 Jul 2017 16:56:10 +0200
|
||||
Subject: lib: add uevent_next_seqnum()
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/kobject.h | 5 +++++
|
||||
lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/lib/kobject_uevent.c
|
||||
+++ b/lib/kobject_uevent.c
|
||||
@@ -179,6 +179,18 @@ out:
|
||||
return r;
|
||||
}
|
||||
|
||||
+u64 uevent_next_seqnum(void)
|
||||
+{
|
||||
+ u64 seq;
|
||||
+
|
||||
+ mutex_lock(&uevent_sock_mutex);
|
||||
+ seq = ++uevent_seqnum;
|
||||
+ mutex_unlock(&uevent_sock_mutex);
|
||||
+
|
||||
+ return seq;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
|
||||
+
|
||||
/**
|
||||
* kobject_synth_uevent - send synthetic uevent with arguments
|
||||
*
|
||||
@ -0,0 +1,76 @@
|
||||
From 0d37e6edc09c99e683dd91ca0e83bbc0df8477b3 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sun, 16 Jul 2017 16:56:10 +0200
|
||||
Subject: lib: add uevent_next_seqnum()
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
include/linux/kobject.h | 5 +++++
|
||||
lib/kobject_uevent.c | 37 +++++++++++++++++++++++++++++++++++++
|
||||
2 files changed, 42 insertions(+)
|
||||
|
||||
--- a/include/linux/kobject.h
|
||||
+++ b/include/linux/kobject.h
|
||||
@@ -32,6 +32,8 @@
|
||||
#define UEVENT_NUM_ENVP 32 /* number of env pointers */
|
||||
#define UEVENT_BUFFER_SIZE 2048 /* buffer for the variables */
|
||||
|
||||
+struct sk_buff;
|
||||
+
|
||||
#ifdef CONFIG_UEVENT_HELPER
|
||||
/* path to the userspace helper executed on an event */
|
||||
extern char uevent_helper[];
|
||||
@@ -245,4 +247,7 @@ int kobject_synth_uevent(struct kobject
|
||||
__printf(2, 3)
|
||||
int add_uevent_var(struct kobj_uevent_env *env, const char *format, ...);
|
||||
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation);
|
||||
+
|
||||
#endif /* _KOBJECT_H_ */
|
||||
--- a/lib/kobject_uevent.c
|
||||
+++ b/lib/kobject_uevent.c
|
||||
@@ -690,6 +690,43 @@ int add_uevent_var(struct kobj_uevent_en
|
||||
EXPORT_SYMBOL_GPL(add_uevent_var);
|
||||
|
||||
#if defined(CONFIG_NET)
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation)
|
||||
+{
|
||||
+ struct uevent_sock *ue_sk;
|
||||
+ int err = 0;
|
||||
+
|
||||
+ /* send netlink message */
|
||||
+ mutex_lock(&uevent_sock_mutex);
|
||||
+ list_for_each_entry(ue_sk, &uevent_sock_list, list) {
|
||||
+ struct sock *uevent_sock = ue_sk->sk;
|
||||
+ struct sk_buff *skb2;
|
||||
+
|
||||
+ skb2 = skb_clone(skb, allocation);
|
||||
+ if (!skb2)
|
||||
+ break;
|
||||
+
|
||||
+ err = netlink_broadcast(uevent_sock, skb2, pid, group,
|
||||
+ allocation);
|
||||
+ if (err)
|
||||
+ break;
|
||||
+ }
|
||||
+ mutex_unlock(&uevent_sock_mutex);
|
||||
+
|
||||
+ kfree_skb(skb);
|
||||
+ return err;
|
||||
+}
|
||||
+#else
|
||||
+int broadcast_uevent(struct sk_buff *skb, __u32 pid, __u32 group,
|
||||
+ gfp_t allocation)
|
||||
+{
|
||||
+ kfree_skb(skb);
|
||||
+ return 0;
|
||||
+}
|
||||
+#endif
|
||||
+EXPORT_SYMBOL_GPL(broadcast_uevent);
|
||||
+
|
||||
+#if defined(CONFIG_NET)
|
||||
static int uevent_net_broadcast(struct sock *usk, struct sk_buff *skb,
|
||||
struct netlink_ext_ack *extack)
|
||||
{
|
||||
@ -0,0 +1,40 @@
|
||||
From 5d301596fdc72f6cb672f72eb3c66e7cddefb103 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 8 Jul 2017 08:26:02 +0200
|
||||
Subject: initramfs: always create console node
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
usr/gen_initramfs_list.sh | 14 ++++++++++++++
|
||||
1 file changed, 14 insertions(+)
|
||||
|
||||
--- a/usr/gen_initramfs_list.sh
|
||||
+++ b/usr/gen_initramfs_list.sh
|
||||
@@ -59,6 +59,18 @@ default_initramfs() {
|
||||
EOF
|
||||
}
|
||||
|
||||
+list_openwrt_initramfs() {
|
||||
+ :
|
||||
+}
|
||||
+
|
||||
+openwrt_initramfs() {
|
||||
+ # make sure that /dev/console exists
|
||||
+ cat <<-EOF >> ${output}
|
||||
+ dir /dev 0755 0 0
|
||||
+ nod /dev/console 0600 0 0 c 5 1
|
||||
+ EOF
|
||||
+}
|
||||
+
|
||||
filetype() {
|
||||
local argv1="$1"
|
||||
|
||||
@@ -180,6 +192,8 @@ dir_filelist() {
|
||||
if [ "$(echo "${dirlist}" | wc -l)" -gt 1 ]; then
|
||||
${dep_list}print_mtime "$1"
|
||||
|
||||
+ ${dep_list}openwrt_initramfs
|
||||
+
|
||||
echo "${dirlist}" | \
|
||||
while read x; do
|
||||
${dep_list}parse ${x}
|
||||
@ -0,0 +1,322 @@
|
||||
--- a/include/net/netfilter/nf_conntrack_ecache.h
|
||||
+++ b/include/net/netfilter/nf_conntrack_ecache.h
|
||||
@@ -72,6 +72,10 @@ struct nf_ct_event {
|
||||
int report;
|
||||
};
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+extern int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb);
|
||||
+extern int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb);
|
||||
+#else
|
||||
struct nf_ct_event_notifier {
|
||||
int (*fcn)(unsigned int events, struct nf_ct_event *item);
|
||||
};
|
||||
@@ -80,7 +84,7 @@ int nf_conntrack_register_notifier(struc
|
||||
struct nf_ct_event_notifier *nb);
|
||||
void nf_conntrack_unregister_notifier(struct net *net,
|
||||
struct nf_ct_event_notifier *nb);
|
||||
-
|
||||
+#endif
|
||||
void nf_ct_deliver_cached_events(struct nf_conn *ct);
|
||||
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
|
||||
u32 portid, int report);
|
||||
@@ -105,12 +109,15 @@ static inline void
|
||||
nf_conntrack_event_cache(enum ip_conntrack_events event, struct nf_conn *ct)
|
||||
{
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
- struct net *net = nf_ct_net(ct);
|
||||
struct nf_conntrack_ecache *e;
|
||||
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+ struct net *net = nf_ct_net(ct);
|
||||
|
||||
if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
|
||||
return;
|
||||
|
||||
+#endif
|
||||
+
|
||||
e = nf_ct_ecache_find(ct);
|
||||
if (e == NULL)
|
||||
return;
|
||||
@@ -123,31 +130,28 @@ static inline int
|
||||
nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
|
||||
u32 portid, int report)
|
||||
{
|
||||
-#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
const struct net *net = nf_ct_net(ct);
|
||||
|
||||
if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
|
||||
return 0;
|
||||
-
|
||||
- return nf_conntrack_eventmask_report(1 << event, ct, portid, report);
|
||||
-#else
|
||||
- return 0;
|
||||
#endif
|
||||
+
|
||||
+ return nf_conntrack_eventmask_report(1 << event, ct, portid, report);
|
||||
}
|
||||
|
||||
static inline int
|
||||
nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
|
||||
{
|
||||
-#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
+#ifndef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
const struct net *net = nf_ct_net(ct);
|
||||
|
||||
if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
|
||||
return 0;
|
||||
|
||||
- return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
|
||||
-#else
|
||||
- return 0;
|
||||
#endif
|
||||
+
|
||||
+ return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
--- a/include/net/netns/conntrack.h
|
||||
+++ b/include/net/netns/conntrack.h
|
||||
@@ -112,7 +112,11 @@ struct netns_ct {
|
||||
|
||||
struct ct_pcpu __percpu *pcpu_lists;
|
||||
struct ip_conntrack_stat __percpu *stat;
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+ struct atomic_notifier_head nf_conntrack_chain;
|
||||
+#else
|
||||
struct nf_ct_event_notifier __rcu *nf_conntrack_event_cb;
|
||||
+#endif
|
||||
struct nf_exp_event_notifier __rcu *nf_expect_event_cb;
|
||||
struct nf_ip_net nf_ct_proto;
|
||||
#if defined(CONFIG_NF_CONNTRACK_LABELS)
|
||||
--- a/net/netfilter/Kconfig
|
||||
+++ b/net/netfilter/Kconfig
|
||||
@@ -148,6 +148,14 @@ config NF_CONNTRACK_RTCACHE
|
||||
To compile it as a module, choose M here. If unsure, say N.
|
||||
The module will be called nf_conntrack_rtcache.
|
||||
|
||||
+config NF_CONNTRACK_CHAIN_EVENTS
|
||||
+ bool "Register multiple callbacks to ct events"
|
||||
+ depends on NF_CONNTRACK_EVENTS
|
||||
+ help
|
||||
+ Support multiple registrations.
|
||||
+
|
||||
+ If unsure, say `N'.
|
||||
+
|
||||
config NF_CONNTRACK_TIMEOUT
|
||||
bool 'Connection tracking timeout'
|
||||
depends on NETFILTER_ADVANCED
|
||||
--- a/net/netfilter/nf_conntrack_core.c
|
||||
+++ b/net/netfilter/nf_conntrack_core.c
|
||||
@@ -2523,6 +2523,9 @@ int nf_conntrack_init_net(struct net *ne
|
||||
nf_conntrack_helper_pernet_init(net);
|
||||
nf_conntrack_proto_pernet_init(net);
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+ ATOMIC_INIT_NOTIFIER_HEAD(&net->ct.nf_conntrack_chain);
|
||||
+#endif
|
||||
return 0;
|
||||
|
||||
err_expect:
|
||||
--- a/net/netfilter/nf_conntrack_ecache.c
|
||||
+++ b/net/netfilter/nf_conntrack_ecache.c
|
||||
@@ -17,6 +17,9 @@
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/percpu.h>
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+#include <linux/notifier.h>
|
||||
+#endif
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/slab.h>
|
||||
@@ -117,6 +120,38 @@ static void ecache_work(struct work_stru
|
||||
schedule_delayed_work(&ctnet->ecache_dwork, delay);
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+int
|
||||
+nf_conntrack_eventmask_report(unsigned int eventmask,
|
||||
+ struct nf_conn *ct,
|
||||
+ u32 portid,
|
||||
+ int report)
|
||||
+{
|
||||
+ struct nf_conntrack_ecache *e;
|
||||
+ struct net *net = nf_ct_net(ct);
|
||||
+
|
||||
+ e = nf_ct_ecache_find(ct);
|
||||
+ if (e == NULL)
|
||||
+ return 0;
|
||||
+
|
||||
+ if (nf_ct_is_confirmed(ct)) {
|
||||
+ struct nf_ct_event item = {
|
||||
+ .ct = ct,
|
||||
+ .portid = e->portid ? e->portid : portid,
|
||||
+ .report = report
|
||||
+ };
|
||||
+ /* This is a resent of a destroy event? If so, skip missed */
|
||||
+ unsigned long missed = e->portid ? 0 : e->missed;
|
||||
+
|
||||
+ if (!((eventmask | missed) & e->ctmask))
|
||||
+ return 0;
|
||||
+
|
||||
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain, eventmask | missed, &item);
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+#else
|
||||
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
|
||||
u32 portid, int report)
|
||||
{
|
||||
@@ -171,10 +206,52 @@ out_unlock:
|
||||
rcu_read_unlock();
|
||||
return ret;
|
||||
}
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_eventmask_report);
|
||||
|
||||
/* deliver cached events and clear cache entry - must be called with locally
|
||||
* disabled softirqs */
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+void nf_ct_deliver_cached_events(struct nf_conn *ct)
|
||||
+{
|
||||
+ unsigned long events, missed;
|
||||
+ struct nf_conntrack_ecache *e;
|
||||
+ struct nf_ct_event item;
|
||||
+ struct net *net = nf_ct_net(ct);
|
||||
+
|
||||
+ e = nf_ct_ecache_find(ct);
|
||||
+ if (e == NULL)
|
||||
+ return;
|
||||
+
|
||||
+ events = xchg(&e->cache, 0);
|
||||
+
|
||||
+ if (!nf_ct_is_confirmed(ct) || nf_ct_is_dying(ct) || !events)
|
||||
+ return;
|
||||
+
|
||||
+ /* We make a copy of the missed event cache without taking
|
||||
+ * the lock, thus we may send missed events twice. However,
|
||||
+ * this does not harm and it happens very rarely. */
|
||||
+ missed = e->missed;
|
||||
+
|
||||
+ if (!((events | missed) & e->ctmask))
|
||||
+ return;
|
||||
+
|
||||
+ item.ct = ct;
|
||||
+ item.portid = 0;
|
||||
+ item.report = 0;
|
||||
+
|
||||
+ atomic_notifier_call_chain(&net->ct.nf_conntrack_chain,
|
||||
+ events | missed,
|
||||
+ &item);
|
||||
+
|
||||
+ if (likely(!missed))
|
||||
+ return;
|
||||
+
|
||||
+ spin_lock_bh(&ct->lock);
|
||||
+ e->missed &= ~missed;
|
||||
+ spin_unlock_bh(&ct->lock);
|
||||
+}
|
||||
+#else
|
||||
void nf_ct_deliver_cached_events(struct nf_conn *ct)
|
||||
{
|
||||
struct net *net = nf_ct_net(ct);
|
||||
@@ -225,6 +302,7 @@ void nf_ct_deliver_cached_events(struct
|
||||
out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(nf_ct_deliver_cached_events);
|
||||
|
||||
void nf_ct_expect_event_report(enum ip_conntrack_expect_events event,
|
||||
@@ -257,6 +335,12 @@ out_unlock:
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+int nf_conntrack_register_notifier(struct net *net, struct notifier_block *nb)
|
||||
+{
|
||||
+ return atomic_notifier_chain_register(&net->ct.nf_conntrack_chain, nb);
|
||||
+}
|
||||
+#else
|
||||
int nf_conntrack_register_notifier(struct net *net,
|
||||
struct nf_ct_event_notifier *new)
|
||||
{
|
||||
@@ -277,8 +361,15 @@ out_unlock:
|
||||
mutex_unlock(&nf_ct_ecache_mutex);
|
||||
return ret;
|
||||
}
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_register_notifier);
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+int nf_conntrack_unregister_notifier(struct net *net, struct notifier_block *nb)
|
||||
+{
|
||||
+ return atomic_notifier_chain_unregister(&net->ct.nf_conntrack_chain, nb);
|
||||
+}
|
||||
+#else
|
||||
void nf_conntrack_unregister_notifier(struct net *net,
|
||||
struct nf_ct_event_notifier *new)
|
||||
{
|
||||
@@ -292,6 +383,7 @@ void nf_conntrack_unregister_notifier(st
|
||||
mutex_unlock(&nf_ct_ecache_mutex);
|
||||
/* synchronize_rcu() is called from ctnetlink_exit. */
|
||||
}
|
||||
+#endif
|
||||
EXPORT_SYMBOL_GPL(nf_conntrack_unregister_notifier);
|
||||
|
||||
int nf_ct_expect_register_notifier(struct net *net,
|
||||
--- a/net/netfilter/nf_conntrack_netlink.c
|
||||
+++ b/net/netfilter/nf_conntrack_netlink.c
|
||||
@@ -28,6 +28,11 @@
|
||||
#include <linux/netlink.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/interrupt.h>
|
||||
+
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+#include <linux/notifier.h>
|
||||
+#endif
|
||||
+
|
||||
#include <linux/slab.h>
|
||||
#include <linux/siphash.h>
|
||||
|
||||
@@ -676,14 +681,22 @@ static size_t ctnetlink_nlmsg_size(const
|
||||
;
|
||||
}
|
||||
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+static int ctnetlink_conntrack_event(struct notifier_block *this,
|
||||
+ unsigned long events, void *ptr)
|
||||
+#else
|
||||
static int
|
||||
ctnetlink_conntrack_event(unsigned int events, struct nf_ct_event *item)
|
||||
+#endif
|
||||
{
|
||||
const struct nf_conntrack_zone *zone;
|
||||
struct net *net;
|
||||
struct nlmsghdr *nlh;
|
||||
struct nfgenmsg *nfmsg;
|
||||
struct nlattr *nest_parms;
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+ struct nf_ct_event *item = (struct nf_ct_event *)ptr;
|
||||
+#endif
|
||||
struct nf_conn *ct = item->ct;
|
||||
struct sk_buff *skb;
|
||||
unsigned int type;
|
||||
@@ -3502,9 +3515,15 @@ static int ctnetlink_stat_exp_cpu(struct
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NF_CONNTRACK_EVENTS
|
||||
+#ifdef CONFIG_NF_CONNTRACK_CHAIN_EVENTS
|
||||
+static struct notifier_block ctnl_notifier = {
|
||||
+ .notifier_call = ctnetlink_conntrack_event,
|
||||
+};
|
||||
+#else
|
||||
static struct nf_ct_event_notifier ctnl_notifier = {
|
||||
.fcn = ctnetlink_conntrack_event,
|
||||
};
|
||||
+#endif
|
||||
|
||||
static struct nf_exp_event_notifier ctnl_notifier_exp = {
|
||||
.fcn = ctnetlink_expect_event,
|
||||
11
target/linux/generic/hack-5.4/999-thermal-tristate.patch
Normal file
11
target/linux/generic/hack-5.4/999-thermal-tristate.patch
Normal file
@ -0,0 +1,11 @@
|
||||
--- a/drivers/thermal/Kconfig
|
||||
+++ b/drivers/thermal/Kconfig
|
||||
@@ -4,7 +4,7 @@
|
||||
#
|
||||
|
||||
menuconfig THERMAL
|
||||
- bool "Generic Thermal sysfs driver"
|
||||
+ tristate "Generic Thermal sysfs driver"
|
||||
help
|
||||
Generic Thermal Sysfs driver offers a generic mechanism for
|
||||
thermal management. Usually it's made up of one or more thermal
|
||||
@ -0,0 +1,26 @@
|
||||
From d9c8bc8c1408f3e8529db6e4e04017b4c579c342 Mon Sep 17 00:00:00 2001
|
||||
From: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
Date: Sun, 18 Feb 2018 17:08:04 +0100
|
||||
Subject: [PATCH] w1: gpio: fix problem with platfom data in w1-gpio
|
||||
|
||||
In devices, where fdt is used, is impossible to apply platform data
|
||||
without proper fdt node.
|
||||
|
||||
This patch allow to use platform data in devices with fdt.
|
||||
|
||||
Signed-off-by: Pawel Dembicki <paweldembicki@gmail.com>
|
||||
---
|
||||
drivers/w1/masters/w1-gpio.c | 7 +++----
|
||||
1 file changed, 3 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/w1/masters/w1-gpio.c
|
||||
+++ b/drivers/w1/masters/w1-gpio.c
|
||||
@@ -76,7 +76,7 @@ static int w1_gpio_probe(struct platform
|
||||
enum gpiod_flags gflags = GPIOD_OUT_LOW_OPEN_DRAIN;
|
||||
int err;
|
||||
|
||||
- if (of_have_populated_dt()) {
|
||||
+ if (of_have_populated_dt() && !dev_get_platdata(&pdev->dev)) {
|
||||
pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
|
||||
if (!pdata)
|
||||
return -ENOMEM;
|
||||
@ -0,0 +1,57 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 18 Apr 2018 10:50:05 +0200
|
||||
Subject: [PATCH] MIPS: only process negative stack offsets on stack traces
|
||||
|
||||
Fixes endless back traces in cases where the compiler emits a stack
|
||||
pointer increase in a branch delay slot (probably for some form of
|
||||
function return).
|
||||
|
||||
[ 3.475442] BUG: MAX_STACK_TRACE_ENTRIES too low!
|
||||
[ 3.480070] turning off the locking correctness validator.
|
||||
[ 3.485521] CPU: 0 PID: 1 Comm: swapper/0 Not tainted 4.14.34 #0
|
||||
[ 3.491475] Stack : 00000000 00000000 00000000 00000000 80e0fce2 00000034 00000000 00000000
|
||||
[ 3.499764] 87c3838c 80696377 8061047c 00000000 00000001 00000001 87c2d850 6534689f
|
||||
[ 3.508059] 00000000 00000000 80e10000 00000000 00000000 000000cf 0000000f 00000000
|
||||
[ 3.516353] 00000000 806a0000 00076891 00000000 00000000 00000000 ffffffff 00000000
|
||||
[ 3.524648] 806c0000 00000004 80e10000 806a0000 00000003 80690000 00000000 80700000
|
||||
[ 3.532942] ...
|
||||
[ 3.535362] Call Trace:
|
||||
[ 3.537818] [<80010a48>] show_stack+0x58/0x100
|
||||
[ 3.542207] [<804c2f78>] dump_stack+0xe8/0x170
|
||||
[ 3.546613] [<80079f90>] save_trace+0xf0/0x110
|
||||
[ 3.551010] [<8007b1ec>] mark_lock+0x33c/0x78c
|
||||
[ 3.555413] [<8007bf48>] __lock_acquire+0x2ac/0x1a08
|
||||
[ 3.560337] [<8007de60>] lock_acquire+0x64/0x8c
|
||||
[ 3.564846] [<804e1570>] _raw_spin_lock_irqsave+0x54/0x78
|
||||
[ 3.570186] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.574770] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.579257] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.583839] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.588329] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.592911] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.597401] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.601983] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.606473] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.611055] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.615545] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.620125] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.624619] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.629197] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.633691] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
[ 3.638269] [<801b7b10>] sysfs_notify+0x74/0xa0
|
||||
[ 3.642763] [<801b618c>] kernfs_notify+0x94/0xac
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/arch/mips/kernel/process.c
|
||||
+++ b/arch/mips/kernel/process.c
|
||||
@@ -365,6 +365,8 @@ static inline int is_sp_move_ins(union m
|
||||
|
||||
if (ip->i_format.opcode == addiu_op ||
|
||||
ip->i_format.opcode == daddiu_op) {
|
||||
+ if (ip->i_format.simmediate > 0)
|
||||
+ return 0;
|
||||
*frame_size = -ip->i_format.simmediate;
|
||||
return 1;
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
From: Florian Fainelli <florian@openwrt.org>
|
||||
Subject: USB: EHCI: add ignore_oc flag to disable overcurrent checking
|
||||
|
||||
This patch adds an ignore_oc flag which can be set by EHCI controller
|
||||
not supporting or wanting to disable overcurrent checking. The EHCI
|
||||
platform data in include/linux/usb/ehci_pdriver.h is also augmented to
|
||||
take advantage of this new flag.
|
||||
|
||||
Signed-off-by: Florian Fainelli <florian@openwrt.org>
|
||||
---
|
||||
drivers/usb/host/ehci-hcd.c | 2 +-
|
||||
drivers/usb/host/ehci-hub.c | 4 ++--
|
||||
drivers/usb/host/ehci-platform.c | 1 +
|
||||
drivers/usb/host/ehci.h | 1 +
|
||||
include/linux/usb/ehci_pdriver.h | 1 +
|
||||
5 files changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/usb/host/ehci-hcd.c
|
||||
+++ b/drivers/usb/host/ehci-hcd.c
|
||||
@@ -638,7 +638,7 @@ static int ehci_run (struct usb_hcd *hcd
|
||||
"USB %x.%x started, EHCI %x.%02x%s\n",
|
||||
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
|
||||
temp >> 8, temp & 0xff,
|
||||
- ignore_oc ? ", overcurrent ignored" : "");
|
||||
+ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
|
||||
|
||||
ehci_writel(ehci, INTR_MASK,
|
||||
&ehci->regs->intr_enable); /* Turn On Interrupts */
|
||||
--- a/drivers/usb/host/ehci-hub.c
|
||||
+++ b/drivers/usb/host/ehci-hub.c
|
||||
@@ -641,7 +641,7 @@ ehci_hub_status_data (struct usb_hcd *hc
|
||||
* always set, seem to clear PORT_OCC and PORT_CSC when writing to
|
||||
* PORT_POWER; that's surprising, but maybe within-spec.
|
||||
*/
|
||||
- if (!ignore_oc)
|
||||
+ if (!ignore_oc && !ehci->ignore_oc)
|
||||
mask = PORT_CSC | PORT_PEC | PORT_OCC;
|
||||
else
|
||||
mask = PORT_CSC | PORT_PEC;
|
||||
@@ -1011,7 +1011,7 @@ int ehci_hub_control(
|
||||
if (temp & PORT_PEC)
|
||||
status |= USB_PORT_STAT_C_ENABLE << 16;
|
||||
|
||||
- if ((temp & PORT_OCC) && !ignore_oc){
|
||||
+ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
|
||||
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||
|
||||
/*
|
||||
--- a/drivers/usb/host/ehci-platform.c
|
||||
+++ b/drivers/usb/host/ehci-platform.c
|
||||
@@ -206,6 +206,8 @@ static int ehci_platform_probe(struct pl
|
||||
hcd->has_tt = 1;
|
||||
if (pdata->reset_on_resume)
|
||||
priv->reset_on_resume = true;
|
||||
+ if (pdata->ignore_oc)
|
||||
+ ehci->ignore_oc = 1;
|
||||
|
||||
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||
if (ehci->big_endian_mmio) {
|
||||
--- a/drivers/usb/host/ehci.h
|
||||
+++ b/drivers/usb/host/ehci.h
|
||||
@@ -218,6 +218,7 @@ struct ehci_hcd { /* one per controlle
|
||||
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
||||
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
||||
+ unsigned ignore_oc:1;
|
||||
|
||||
/* required for usb32 quirk */
|
||||
#define OHCI_CTRL_HCFS (3 << 6)
|
||||
--- a/include/linux/usb/ehci_pdriver.h
|
||||
+++ b/include/linux/usb/ehci_pdriver.h
|
||||
@@ -50,6 +50,7 @@ struct usb_ehci_pdata {
|
||||
unsigned no_io_watchdog:1;
|
||||
unsigned reset_on_resume:1;
|
||||
unsigned dma_mask_64:1;
|
||||
+ unsigned ignore_oc:1;
|
||||
|
||||
/* Turn on all power and clocks */
|
||||
int (*power_on)(struct platform_device *pdev);
|
||||
@ -0,0 +1,82 @@
|
||||
From: Tobias Wolf <dev-NTEO@vplace.de>
|
||||
Subject: mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET calculation
|
||||
|
||||
An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
|
||||
kernel beyond version 4.3 resulting in:
|
||||
|
||||
BUG: Bad page state in process swapper pfn:086ac
|
||||
|
||||
bisect resulted in:
|
||||
|
||||
a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
|
||||
commit a1c34a3bf00af2cede839879502e12dc68491ad5
|
||||
Author: Laura Abbott <laura@labbott.name>
|
||||
Date: Thu Nov 5 18:48:46 2015 -0800
|
||||
|
||||
mm: Don't offset memmap for flatmem
|
||||
|
||||
Srinivas Kandagatla reported bad page messages when trying to remove the
|
||||
bottom 2MB on an ARM based IFC6410 board
|
||||
|
||||
BUG: Bad page state in process swapper pfn:fffa8
|
||||
page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0
|
||||
flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
|
||||
page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
|
||||
bad because of flags:
|
||||
flags: 0x200041(locked|active|mlocked)
|
||||
Modules linked in:
|
||||
CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
|
||||
#816
|
||||
Hardware name: Qualcomm (Flattened Device Tree)
|
||||
unwind_backtrace
|
||||
show_stack
|
||||
dump_stack
|
||||
bad_page
|
||||
free_pages_prepare
|
||||
free_hot_cold_page
|
||||
__free_pages
|
||||
free_highmem_page
|
||||
mem_init
|
||||
start_kernel
|
||||
Disabling lock debugging due to kernel taint
|
||||
[...]
|
||||
:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
|
||||
0a8156f848733dfa21e16c196dfb6c0a76290709 M mm
|
||||
|
||||
This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
|
||||
page_to_pfn anymore.
|
||||
|
||||
The following output was generated with two hacked in printk statements:
|
||||
|
||||
printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
|
||||
(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||
printk("after %p\n", mem_map);
|
||||
|
||||
Output:
|
||||
|
||||
[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280
|
||||
[ 0.000000] after 8851b280
|
||||
|
||||
As seen in the first line mem_map with subtraction of offset does not equal the
|
||||
mem_map after subtraction of ARCH_PFN_OFFSET.
|
||||
|
||||
After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
|
||||
previously calculated offset is zero for the named platform it is able to boot
|
||||
4.4 and 4.9-rc7 again.
|
||||
|
||||
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||
---
|
||||
|
||||
--- a/mm/page_alloc.c
|
||||
+++ b/mm/page_alloc.c
|
||||
@@ -6851,7 +6851,7 @@ static void __ref alloc_node_mem_map(str
|
||||
mem_map = NODE_DATA(0)->node_mem_map;
|
||||
#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
|
||||
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||
- mem_map -= offset;
|
||||
+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||
#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,18 @@
|
||||
From: Giuseppe Lippolis <giu.lippolis@gmail.com>
|
||||
Subject: Add the linux,spidev compatible in spidev Several device in ramips have this binding in the dts
|
||||
|
||||
Signed-off-by: Giuseppe Lippolis <giu.lippolis@gmail.com>
|
||||
---
|
||||
drivers/spi/spidev.c | 1 +
|
||||
1 file changed, 1 insertion(+)
|
||||
|
||||
--- a/drivers/spi/spidev.c
|
||||
+++ b/drivers/spi/spidev.c
|
||||
@@ -673,6 +673,7 @@ static const struct of_device_id spidev_
|
||||
{ .compatible = "lwn,bk4" },
|
||||
{ .compatible = "dh,dhcom-board" },
|
||||
{ .compatible = "menlo,m53cpld" },
|
||||
+ { .compatible = "siliconlabs,si3210" },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
||||
@ -0,0 +1,62 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: jffs2: use .rename2 and add RENAME_WHITEOUT support
|
||||
|
||||
It is required for renames on overlayfs
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -752,6 +752,24 @@ static int jffs2_mknod (struct inode *di
|
||||
return ret;
|
||||
}
|
||||
|
||||
+static int jffs2_whiteout (struct inode *old_dir, struct dentry *old_dentry)
|
||||
+{
|
||||
+ struct dentry *wh;
|
||||
+ int err;
|
||||
+
|
||||
+ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
|
||||
+ if (!wh)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
|
||||
+ WHITEOUT_DEV);
|
||||
+ if (err)
|
||||
+ return err;
|
||||
+
|
||||
+ d_rehash(wh);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||
struct inode *new_dir_i, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
@@ -762,7 +780,7 @@ static int jffs2_rename (struct inode *o
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
- if (flags & ~RENAME_NOREPLACE)
|
||||
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||
return -EINVAL;
|
||||
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
@@ -828,9 +846,14 @@ static int jffs2_rename (struct inode *o
|
||||
if (d_is_dir(old_dentry) && !victim_f)
|
||||
inc_nlink(new_dir_i);
|
||||
|
||||
- /* Unlink the original */
|
||||
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
|
||||
+ if (flags & RENAME_WHITEOUT)
|
||||
+ /* Replace with whiteout */
|
||||
+ ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||
+ else
|
||||
+ /* Unlink the original */
|
||||
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
+ old_dentry->d_name.name,
|
||||
+ old_dentry->d_name.len, NULL, now);
|
||||
|
||||
/* We don't touch inode->i_nlink */
|
||||
|
||||
@ -0,0 +1,73 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: jffs2: add RENAME_EXCHANGE support
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/fs/jffs2/dir.c
|
||||
+++ b/fs/jffs2/dir.c
|
||||
@@ -777,18 +777,31 @@ static int jffs2_rename (struct inode *o
|
||||
int ret;
|
||||
struct jffs2_sb_info *c = JFFS2_SB_INFO(old_dir_i->i_sb);
|
||||
struct jffs2_inode_info *victim_f = NULL;
|
||||
+ struct inode *fst_inode = d_inode(old_dentry);
|
||||
+ struct inode *snd_inode = d_inode(new_dentry);
|
||||
uint8_t type;
|
||||
uint32_t now;
|
||||
|
||||
- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
|
||||
return -EINVAL;
|
||||
|
||||
+ if ((flags & RENAME_EXCHANGE) && (old_dir_i != new_dir_i)) {
|
||||
+ if (S_ISDIR(fst_inode->i_mode) && !S_ISDIR(snd_inode->i_mode)) {
|
||||
+ inc_nlink(new_dir_i);
|
||||
+ drop_nlink(old_dir_i);
|
||||
+ }
|
||||
+ else if (!S_ISDIR(fst_inode->i_mode) && S_ISDIR(snd_inode->i_mode)) {
|
||||
+ drop_nlink(new_dir_i);
|
||||
+ inc_nlink(old_dir_i);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* The VFS will check for us and prevent trying to rename a
|
||||
* file over a directory and vice versa, but if it's a directory,
|
||||
* the VFS can't check whether the victim is empty. The filesystem
|
||||
* needs to do that for itself.
|
||||
*/
|
||||
- if (d_really_is_positive(new_dentry)) {
|
||||
+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
|
||||
victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
|
||||
if (d_is_dir(new_dentry)) {
|
||||
struct jffs2_full_dirent *fd;
|
||||
@@ -823,7 +836,7 @@ static int jffs2_rename (struct inode *o
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
- if (victim_f) {
|
||||
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
|
||||
/* There was a victim. Kill it off nicely */
|
||||
if (d_is_dir(new_dentry))
|
||||
clear_nlink(d_inode(new_dentry));
|
||||
@@ -849,6 +862,12 @@ static int jffs2_rename (struct inode *o
|
||||
if (flags & RENAME_WHITEOUT)
|
||||
/* Replace with whiteout */
|
||||
ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||
+ else if (flags & RENAME_EXCHANGE)
|
||||
+ /* Replace the original */
|
||||
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
+ d_inode(new_dentry)->i_ino, type,
|
||||
+ old_dentry->d_name.name, old_dentry->d_name.len,
|
||||
+ now);
|
||||
else
|
||||
/* Unlink the original */
|
||||
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||
@@ -880,7 +899,7 @@ static int jffs2_rename (struct inode *o
|
||||
return ret;
|
||||
}
|
||||
|
||||
- if (d_is_dir(old_dentry))
|
||||
+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
|
||||
drop_nlink(old_dir_i);
|
||||
|
||||
new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
|
||||
@ -0,0 +1,45 @@
|
||||
From: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Subject: bridge: allow receiption on disabled port
|
||||
|
||||
When an ethernet device is enslaved to a bridge, and the bridge STP
|
||||
detects loss of carrier (or operational state down), then normally
|
||||
packet receiption is blocked.
|
||||
|
||||
This breaks control applications like WPA which maybe expecting to
|
||||
receive packets to negotiate to bring link up. The bridge needs to
|
||||
block forwarding packets from these disabled ports, but there is no
|
||||
hard requirement to not allow local packet delivery.
|
||||
|
||||
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/net/bridge/br_input.c
|
||||
+++ b/net/bridge/br_input.c
|
||||
@@ -190,6 +190,9 @@ static void __br_handle_local_finish(str
|
||||
/* note: already called with rcu_read_lock */
|
||||
static int br_handle_local_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
+ struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||
+
|
||||
+ if (p->state != BR_STATE_DISABLED)
|
||||
__br_handle_local_finish(skb);
|
||||
|
||||
/* return 1 to signal the okfn() was called so it's ok to use the skb */
|
||||
@@ -340,6 +343,17 @@ rx_handler_result_t br_handle_frame(stru
|
||||
|
||||
forward:
|
||||
switch (p->state) {
|
||||
+ case BR_STATE_DISABLED:
|
||||
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
+ skb->pkt_type = PACKET_HOST;
|
||||
+
|
||||
+ if (NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
|
||||
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||
+ br_handle_local_finish) == 1) {
|
||||
+ return RX_HANDLER_PASS;
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
case BR_STATE_FORWARDING:
|
||||
case BR_STATE_LEARNING:
|
||||
if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||
@ -0,0 +1,63 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: net: phy: at803x: add support for AT8032
|
||||
|
||||
Like AT8030, this PHY needs the GPIO reset workaround
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/drivers/net/phy/at803x.c
|
||||
+++ b/drivers/net/phy/at803x.c
|
||||
@@ -64,8 +64,10 @@
|
||||
|
||||
#define ATH8030_PHY_ID 0x004dd076
|
||||
#define ATH8031_PHY_ID 0x004dd074
|
||||
+#define ATH8032_PHY_ID 0x004dd023
|
||||
#define ATH8035_PHY_ID 0x004dd072
|
||||
#define AT803X_PHY_ID_MASK 0xffffffef
|
||||
+#define AT8032_PHY_ID_MASK 0xffffffff
|
||||
|
||||
MODULE_DESCRIPTION("Atheros 803x PHY driver");
|
||||
MODULE_AUTHOR("Matus Ujhelyi");
|
||||
@@ -314,7 +316,7 @@ static int at803x_config_intr(struct phy
|
||||
static void at803x_link_change_notify(struct phy_device *phydev)
|
||||
{
|
||||
/*
|
||||
- * Conduct a hardware reset for AT8030 every time a link loss is
|
||||
+ * Conduct a hardware reset for AT8030/2 every time a link loss is
|
||||
* signalled. This is necessary to circumvent a hardware bug that
|
||||
* occurs when the cable is unplugged while TX packets are pending
|
||||
* in the FIFO. In such cases, the FIFO enters an error mode it
|
||||
@@ -471,6 +473,24 @@ static struct phy_driver at803x_driver[]
|
||||
.aneg_done = at803x_aneg_done,
|
||||
.ack_interrupt = &at803x_ack_interrupt,
|
||||
.config_intr = &at803x_config_intr,
|
||||
+}, {
|
||||
+ /* ATHEROS 8032 */
|
||||
+ .phy_id = ATH8032_PHY_ID,
|
||||
+ .name = "Atheros 8032 ethernet",
|
||||
+ .phy_id_mask = AT8032_PHY_ID_MASK,
|
||||
+ .probe = at803x_probe,
|
||||
+ .config_init = at803x_config_init,
|
||||
+ .link_change_notify = at803x_link_change_notify,
|
||||
+ .set_wol = at803x_set_wol,
|
||||
+ .get_wol = at803x_get_wol,
|
||||
+ .suspend = at803x_suspend,
|
||||
+ .resume = at803x_resume,
|
||||
+ /* PHY_BASIC_FEATURES */
|
||||
+ .read_status = at803x_read_status,
|
||||
+ .config_aneg = genphy_config_aneg,
|
||||
+ .read_status = genphy_read_status,
|
||||
+ .ack_interrupt = at803x_ack_interrupt,
|
||||
+ .config_intr = at803x_config_intr,
|
||||
} };
|
||||
|
||||
module_phy_driver(at803x_driver);
|
||||
@@ -478,6 +498,7 @@ module_phy_driver(at803x_driver);
|
||||
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
|
||||
{ ATH8030_PHY_ID, AT803X_PHY_ID_MASK },
|
||||
{ ATH8031_PHY_ID, AT803X_PHY_ID_MASK },
|
||||
+ { ATH8032_PHY_ID, AT8032_PHY_ID_MASK },
|
||||
{ ATH8035_PHY_ID, AT803X_PHY_ID_MASK },
|
||||
{ }
|
||||
};
|
||||
@ -0,0 +1,31 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: Upgrade to Linux 2.6.19
|
||||
|
||||
- Includes large parts of the patch from #1021 by dpalffy
|
||||
- Includes RB532 NAND driver changes by n0-1
|
||||
|
||||
[john@phrozen.org: feix will add this to his upstream queue]
|
||||
|
||||
lede-commit: bff468813f78f81e36ebb2a3f4354de7365e640f
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
Makefile | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -701,11 +701,11 @@ KBUILD_CFLAGS += $(call cc-disable-warni
|
||||
KBUILD_CFLAGS += $(call cc-disable-warning, address-of-packed-member)
|
||||
|
||||
ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE
|
||||
-KBUILD_CFLAGS += -O2
|
||||
+KBUILD_CFLAGS += -O2 $(EXTRA_OPTIMIZATION)
|
||||
else ifdef CONFIG_CC_OPTIMIZE_FOR_PERFORMANCE_O3
|
||||
-KBUILD_CFLAGS += -O3
|
||||
+KBUILD_CFLAGS += -O3 $(EXTRA_OPTIMIZATION)
|
||||
else ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||
-KBUILD_CFLAGS += -Os
|
||||
+KBUILD_CFLAGS += -Os -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
|
||||
endif
|
||||
|
||||
ifdef CONFIG_CC_DISABLE_WARN_MAYBE_UNINITIALIZED
|
||||
119
target/linux/generic/pending-5.4/203-kallsyms_uncompressed.patch
Normal file
119
target/linux/generic/pending-5.4/203-kallsyms_uncompressed.patch
Normal file
@ -0,0 +1,119 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: add a config option for keeping the kallsyms table uncompressed, saving ~9kb kernel size after lzma on ar71xx
|
||||
|
||||
[john@phrozen.org: added to my upstream queue 30.12.2016]
|
||||
lede-commit: e0e3509b5ce2ccf93d4d67ea907613f5f7ec2eed
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
init/Kconfig | 11 +++++++++++
|
||||
kernel/kallsyms.c | 8 ++++++++
|
||||
scripts/kallsyms.c | 12 ++++++++++++
|
||||
scripts/link-vmlinux.sh | 4 ++++
|
||||
4 files changed, 35 insertions(+)
|
||||
|
||||
--- a/init/Kconfig
|
||||
+++ b/init/Kconfig
|
||||
@@ -1295,6 +1295,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
|
||||
the unaligned access emulation.
|
||||
see arch/parisc/kernel/unaligned.c for reference
|
||||
|
||||
+config KALLSYMS_UNCOMPRESSED
|
||||
+ bool "Keep kallsyms uncompressed"
|
||||
+ depends on KALLSYMS
|
||||
+ help
|
||||
+ Normally kallsyms contains compressed symbols (using a token table),
|
||||
+ reducing the uncompressed kernel image size. Keeping the symbol table
|
||||
+ uncompressed significantly improves the size of this part in compressed
|
||||
+ kernel images.
|
||||
+
|
||||
+ Say N unless you need compressed kernel images to be small.
|
||||
+
|
||||
config HAVE_PCSPKR_PLATFORM
|
||||
bool
|
||||
|
||||
--- a/kernel/kallsyms.c
|
||||
+++ b/kernel/kallsyms.c
|
||||
@@ -75,6 +75,11 @@ static unsigned int kallsyms_expand_symb
|
||||
* For every byte on the compressed symbol data, copy the table
|
||||
* entry for that byte.
|
||||
*/
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ memcpy(result, data + 1, len - 1);
|
||||
+ result += len - 1;
|
||||
+ len = 0;
|
||||
+#endif
|
||||
while (len) {
|
||||
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
|
||||
data++;
|
||||
@@ -107,6 +112,9 @@ tail:
|
||||
*/
|
||||
static char kallsyms_get_symbol_type(unsigned int off)
|
||||
{
|
||||
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||
+ return kallsyms_names[off + 1];
|
||||
+#endif
|
||||
/*
|
||||
* Get just the first code, look it up in the token table,
|
||||
* and return the first char from this token.
|
||||
--- a/scripts/kallsyms.c
|
||||
+++ b/scripts/kallsyms.c
|
||||
@@ -59,6 +59,7 @@ static struct addr_range percpu_range =
|
||||
static struct sym_entry *table;
|
||||
static unsigned int table_size, table_cnt;
|
||||
static int all_symbols = 0;
|
||||
+static int uncompressed = 0;
|
||||
static int absolute_percpu = 0;
|
||||
static int base_relative = 0;
|
||||
|
||||
@@ -440,6 +441,9 @@ static void write_src(void)
|
||||
|
||||
free(markers);
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return;
|
||||
+
|
||||
output_label("kallsyms_token_table");
|
||||
off = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
@@ -500,6 +504,9 @@ static void *find_token(unsigned char *s
|
||||
{
|
||||
int i;
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return NULL;
|
||||
+
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
if (str[i] == token[0] && str[i+1] == token[1])
|
||||
return &str[i];
|
||||
@@ -572,6 +579,9 @@ static void optimize_result(void)
|
||||
{
|
||||
int i, best;
|
||||
|
||||
+ if (uncompressed)
|
||||
+ return;
|
||||
+
|
||||
/* using the '\0' symbol last allows compress_symbols to use standard
|
||||
* fast string functions */
|
||||
for (i = 255; i >= 0; i--) {
|
||||
@@ -751,6 +761,8 @@ int main(int argc, char **argv)
|
||||
absolute_percpu = 1;
|
||||
else if (strcmp(argv[i], "--base-relative") == 0)
|
||||
base_relative = 1;
|
||||
+ else if (strcmp(argv[i], "--uncompressed") == 0)
|
||||
+ uncompressed = 1;
|
||||
else
|
||||
usage();
|
||||
}
|
||||
--- a/scripts/link-vmlinux.sh
|
||||
+++ b/scripts/link-vmlinux.sh
|
||||
@@ -152,6 +152,10 @@ kallsyms()
|
||||
kallsymopt="${kallsymopt} --base-relative"
|
||||
fi
|
||||
|
||||
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
|
||||
+ kallsymopt="${kallsymopt} --uncompressed"
|
||||
+ fi
|
||||
+
|
||||
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
||||
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
|
||||
|
||||
@ -0,0 +1,41 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Subject: kernel: when KALLSYMS is disabled, print module address + size for matching backtrace entries
|
||||
|
||||
[john@phrozen.org: felix will add this to his upstream queue]
|
||||
|
||||
lede-commit 53827cdc824556cda910b23ce5030c363b8f1461
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
lib/vsprintf.c | 15 +++++++++++----
|
||||
1 file changed, 11 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/lib/vsprintf.c
|
||||
+++ b/lib/vsprintf.c
|
||||
@@ -907,8 +907,10 @@ char *symbol_string(char *buf, char *end
|
||||
struct printf_spec spec, const char *fmt)
|
||||
{
|
||||
unsigned long value;
|
||||
-#ifdef CONFIG_KALLSYMS
|
||||
char sym[KSYM_SYMBOL_LEN];
|
||||
+#ifndef CONFIG_KALLSYMS
|
||||
+ struct module *mod;
|
||||
+ int len;
|
||||
#endif
|
||||
|
||||
if (fmt[1] == 'R')
|
||||
@@ -925,8 +927,14 @@ char *symbol_string(char *buf, char *end
|
||||
|
||||
return string_nocheck(buf, end, sym, spec);
|
||||
#else
|
||||
- return special_hex_number(buf, end, value, sizeof(void *));
|
||||
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
|
||||
+ mod = __module_address(value);
|
||||
+ if (mod)
|
||||
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
|
||||
+ mod->name, mod->core_layout.base,
|
||||
+ mod->core_layout.size);
|
||||
#endif
|
||||
+ return string(buf, end, sym, spec);
|
||||
}
|
||||
|
||||
static const struct printf_spec default_str_spec = {
|
||||
@ -0,0 +1,47 @@
|
||||
From: Gabor Juhos <juhosg@openwrt.org>
|
||||
Subject: usr: sanitize deps_initramfs list
|
||||
|
||||
If any filename in the intramfs dependency
|
||||
list contains a colon, that causes a kernel
|
||||
build error like this:
|
||||
|
||||
/devel/openwrt/build_dir/linux-ar71xx_generic/linux-3.6.6/usr/Makefile:58: *** multiple target patterns. Stop.
|
||||
make[5]: *** [usr] Error 2
|
||||
|
||||
Fix it by removing such filenames from the
|
||||
deps_initramfs list.
|
||||
|
||||
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||
---
|
||||
usr/Makefile | 8 +++++---
|
||||
1 file changed, 5 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/usr/Makefile
|
||||
+++ b/usr/Makefile
|
||||
@@ -42,21 +42,23 @@ ifneq ($(wildcard $(obj)/$(datafile_d_y)
|
||||
include $(obj)/$(datafile_d_y)
|
||||
endif
|
||||
|
||||
+deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
|
||||
+
|
||||
quiet_cmd_initfs = GEN $@
|
||||
cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
|
||||
|
||||
targets := $(datafile_y)
|
||||
|
||||
# do not try to update files included in initramfs
|
||||
-$(deps_initramfs): ;
|
||||
+$(deps_initramfs_sane): ;
|
||||
|
||||
-$(deps_initramfs): klibcdirs
|
||||
+$(deps_initramfs_sane): klibcdirs
|
||||
# We rebuild initramfs_data.cpio if:
|
||||
# 1) Any included file is newer than initramfs_data.cpio
|
||||
# 2) There are changes in which files are included (added or deleted)
|
||||
# 3) If gen_init_cpio are newer than initramfs_data.cpio
|
||||
# 4) Arguments to gen_initramfs.sh changes
|
||||
-$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
|
||||
+$(obj)/$(datafile_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
|
||||
$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/$(datafile_d_y)
|
||||
$(call if_changed,initfs)
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
From: Imre Kaloz <kaloz@openwrt.org>
|
||||
Subject: [PATCH] hack: net: wireless: make the wl12xx glue code available with
|
||||
compat-wireless, too
|
||||
|
||||
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||
---
|
||||
drivers/net/wireless/ti/Kconfig | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/net/wireless/ti/Kconfig
|
||||
+++ b/drivers/net/wireless/ti/Kconfig
|
||||
@@ -20,7 +20,7 @@ source "drivers/net/wireless/ti/wlcore/K
|
||||
|
||||
config WILINK_PLATFORM_DATA
|
||||
bool "TI WiLink platform data"
|
||||
- depends on WLCORE_SDIO || WL1251_SDIO
|
||||
+ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
|
||||
default y
|
||||
---help---
|
||||
Small platform data bit needed to pass data to the sdio modules.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user