mirror of
https://github.com/openwrt/openwrt.git
synced 2024-12-23 15:32:33 +00:00
kernel: copy kernel 4.19 code to 5.4
No changes were done to the patches while coping them. Currently they do not apply on top of kernel 5.4. Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
This commit is contained in:
parent
955634b473
commit
c16517d26d
@ -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,23 @@
|
||||
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
|
||||
@@ -432,8 +432,8 @@ KBUILD_LDFLAGS :=
|
||||
GCC_PLUGINS_CFLAGS :=
|
||||
CLANG_FLAGS :=
|
||||
|
||||
-export ARCH SRCARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD CC
|
||||
-export CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
|
||||
+export ARCH SRCARCH SUBARCH CONFIG_SHELL HOSTCC KBUILD_HOSTCFLAGS CROSS_COMPILE AS LD
|
||||
+export CC CPP AR NM STRIP OBJCOPY OBJDUMP KBUILD_HOSTLDFLAGS KBUILD_HOSTLDLIBS
|
||||
export MAKE LEX YACC AWK GENKSYMS INSTALLKERNEL PERL PYTHON PYTHON2 PYTHON3 UTS_MACHINE
|
||||
export HOSTCXX KBUILD_HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS
|
||||
|
@ -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
|
||||
@@ -135,6 +135,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
|
||||
@@ -25,6 +25,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
|
||||
+
|
||||
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
||||
|
||||
# netlink interface for nf_conntrack
|
||||
--- /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,58 @@
|
||||
From 1186af457cc186c5ed01708da71b1ffbdf0a2638 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 20 Nov 2018 09:55:45 +0100
|
||||
Subject: [PATCH] mtd: keep original flags for every struct mtd_info
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When allocating a new partition mtd subsystem runs internal tests in the
|
||||
allocate_partition(). They may result in modifying specified flags (e.g.
|
||||
dropping some /features/ like write access).
|
||||
|
||||
Those constraints don't have to be necessary true for subpartitions. It
|
||||
may happen parent partition isn't block aligned (effectively disabling
|
||||
write access) while subpartition may fit blocks nicely. In such case all
|
||||
checks should be run again (starting with original flags value).
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
---
|
||||
drivers/mtd/mtdcore.c | 2 ++
|
||||
drivers/mtd/mtdpart.c | 3 ++-
|
||||
include/linux/mtd/mtd.h | 1 +
|
||||
3 files changed, 5 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/mtd/mtdcore.c
|
||||
+++ b/drivers/mtd/mtdcore.c
|
||||
@@ -665,6 +665,8 @@ static void mtd_set_dev_defaults(struct
|
||||
} else {
|
||||
pr_debug("mtd device won't show a device symlink in sysfs\n");
|
||||
}
|
||||
+
|
||||
+ mtd->orig_flags = mtd->flags;
|
||||
}
|
||||
|
||||
/**
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -346,7 +346,8 @@ static struct mtd_part *allocate_partiti
|
||||
|
||||
/* set up the MTD object for this partition */
|
||||
slave->mtd.type = parent->type;
|
||||
- slave->mtd.flags = parent->flags & ~part->mask_flags;
|
||||
+ slave->mtd.flags = parent->orig_flags & ~part->mask_flags;
|
||||
+ slave->mtd.orig_flags = slave->mtd.flags;
|
||||
slave->mtd.size = part->size;
|
||||
slave->mtd.writesize = parent->writesize;
|
||||
slave->mtd.writebufsize = parent->writebufsize;
|
||||
--- a/include/linux/mtd/mtd.h
|
||||
+++ b/include/linux/mtd/mtd.h
|
||||
@@ -207,6 +207,7 @@ struct mtd_debug_info {
|
||||
struct mtd_info {
|
||||
u_char type;
|
||||
uint32_t flags;
|
||||
+ uint32_t orig_flags; /* Flags as before running mtd checks */
|
||||
uint64_t size; // Total size of the MTD
|
||||
|
||||
/* "Major" erase size for the device. Naïve users may take this
|
@ -0,0 +1,55 @@
|
||||
From 6750f61a13a0197c40e4a40739117493b15f19e8 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Tue, 20 Nov 2018 10:24:09 +0100
|
||||
Subject: [PATCH] mtd: improve calculating partition boundaries when checking
|
||||
for alignment
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
When checking for alignment mtd should check absolute offsets. It's
|
||||
important for subpartitions as it doesn't make sense to check their
|
||||
relative addresses.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
---
|
||||
drivers/mtd/mtdpart.c | 13 +++++++++++--
|
||||
1 file changed, 11 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/mtdpart.c
|
||||
+++ b/drivers/mtd/mtdpart.c
|
||||
@@ -61,6 +61,15 @@ static inline struct mtd_part *mtd_to_pa
|
||||
return container_of(mtd, struct mtd_part, mtd);
|
||||
}
|
||||
|
||||
+static u64 part_absolute_offset(struct mtd_info *mtd)
|
||||
+{
|
||||
+ struct mtd_part *part = mtd_to_part(mtd);
|
||||
+
|
||||
+ if (!mtd_is_partition(mtd))
|
||||
+ return 0;
|
||||
+
|
||||
+ return part_absolute_offset(part->parent) + part->offset;
|
||||
+}
|
||||
|
||||
/*
|
||||
* MTD methods which simply translate the effective address and pass through
|
||||
@@ -518,7 +527,7 @@ static struct mtd_part *allocate_partiti
|
||||
if (!(slave->mtd.flags & MTD_NO_ERASE))
|
||||
wr_alignment = slave->mtd.erasesize;
|
||||
|
||||
- tmp = slave->offset;
|
||||
+ tmp = part_absolute_offset(parent) + slave->offset;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
|
||||
/* Doesn't start on a boundary of major erase size */
|
||||
@@ -529,7 +538,7 @@ static struct mtd_part *allocate_partiti
|
||||
part->name);
|
||||
}
|
||||
|
||||
- tmp = slave->mtd.size;
|
||||
+ tmp = part_absolute_offset(parent) + slave->mtd.size;
|
||||
remainder = do_div(tmp, wr_alignment);
|
||||
if ((slave->mtd.flags & MTD_WRITEABLE) && remainder) {
|
||||
slave->mtd.flags &= ~MTD_WRITEABLE;
|
@ -0,0 +1,199 @@
|
||||
From 5a1c18b761ddb299a06746948b9ec2814b04fa92 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 2 Jan 2019 00:00:01 +0100
|
||||
Subject: [PATCH] bcma: keep a direct pointer to the struct device
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Accessing struct device is pretty useful/common so having a direct
|
||||
pointer:
|
||||
1) Simplifies some code
|
||||
2) Makes bcma_bus_get_host_dev() unneeded
|
||||
3) Allows further improvements like using dev_* printing helpers
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/bcma/bcma_private.h | 1 -
|
||||
drivers/bcma/driver_gpio.c | 2 +-
|
||||
drivers/bcma/host_pci.c | 2 ++
|
||||
drivers/bcma/host_soc.c | 4 ++--
|
||||
drivers/bcma/main.c | 45 +++++++++----------------------------
|
||||
include/linux/bcma/bcma.h | 11 +++------
|
||||
6 files changed, 18 insertions(+), 47 deletions(-)
|
||||
|
||||
--- a/drivers/bcma/bcma_private.h
|
||||
+++ b/drivers/bcma/bcma_private.h
|
||||
@@ -33,7 +33,6 @@ int __init bcma_bus_early_register(struc
|
||||
int bcma_bus_suspend(struct bcma_bus *bus);
|
||||
int bcma_bus_resume(struct bcma_bus *bus);
|
||||
#endif
|
||||
-struct device *bcma_bus_get_host_dev(struct bcma_bus *bus);
|
||||
|
||||
/* scan.c */
|
||||
void bcma_detect_chip(struct bcma_bus *bus);
|
||||
--- a/drivers/bcma/driver_gpio.c
|
||||
+++ b/drivers/bcma/driver_gpio.c
|
||||
@@ -183,7 +183,7 @@ int bcma_gpio_init(struct bcma_drv_cc *c
|
||||
chip->direction_input = bcma_gpio_direction_input;
|
||||
chip->direction_output = bcma_gpio_direction_output;
|
||||
chip->owner = THIS_MODULE;
|
||||
- chip->parent = bcma_bus_get_host_dev(bus);
|
||||
+ chip->parent = bus->dev;
|
||||
#if IS_BUILTIN(CONFIG_OF)
|
||||
chip->of_node = cc->core->dev.of_node;
|
||||
#endif
|
||||
--- a/drivers/bcma/host_pci.c
|
||||
+++ b/drivers/bcma/host_pci.c
|
||||
@@ -196,6 +196,8 @@ static int bcma_host_pci_probe(struct pc
|
||||
goto err_pci_release_regions;
|
||||
}
|
||||
|
||||
+ bus->dev = &dev->dev;
|
||||
+
|
||||
/* Map MMIO */
|
||||
err = -ENOMEM;
|
||||
bus->mmio = pci_iomap(dev, 0, ~0UL);
|
||||
--- a/drivers/bcma/host_soc.c
|
||||
+++ b/drivers/bcma/host_soc.c
|
||||
@@ -179,7 +179,6 @@ int __init bcma_host_soc_register(struct
|
||||
/* Host specific */
|
||||
bus->hosttype = BCMA_HOSTTYPE_SOC;
|
||||
bus->ops = &bcma_host_soc_ops;
|
||||
- bus->host_pdev = NULL;
|
||||
|
||||
/* Initialize struct, detect chip */
|
||||
bcma_init_bus(bus);
|
||||
@@ -213,6 +212,8 @@ static int bcma_host_soc_probe(struct pl
|
||||
if (!bus)
|
||||
return -ENOMEM;
|
||||
|
||||
+ bus->dev = dev;
|
||||
+
|
||||
/* Map MMIO */
|
||||
bus->mmio = of_iomap(np, 0);
|
||||
if (!bus->mmio)
|
||||
@@ -221,7 +222,6 @@ static int bcma_host_soc_probe(struct pl
|
||||
/* Host specific */
|
||||
bus->hosttype = BCMA_HOSTTYPE_SOC;
|
||||
bus->ops = &bcma_host_soc_ops;
|
||||
- bus->host_pdev = pdev;
|
||||
|
||||
/* Initialize struct, detect chip */
|
||||
bcma_init_bus(bus);
|
||||
--- a/drivers/bcma/main.c
|
||||
+++ b/drivers/bcma/main.c
|
||||
@@ -223,8 +223,8 @@ unsigned int bcma_core_irq(struct bcma_d
|
||||
mips_irq = bcma_core_mips_irq(core);
|
||||
return mips_irq <= 4 ? mips_irq + 2 : 0;
|
||||
}
|
||||
- if (bus->host_pdev)
|
||||
- return bcma_of_get_irq(&bus->host_pdev->dev, core, num);
|
||||
+ if (bus->dev)
|
||||
+ return bcma_of_get_irq(bus->dev, core, num);
|
||||
return 0;
|
||||
case BCMA_HOSTTYPE_SDIO:
|
||||
return 0;
|
||||
@@ -239,18 +239,18 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
core->dev.release = bcma_release_core_dev;
|
||||
core->dev.bus = &bcma_bus_type;
|
||||
dev_set_name(&core->dev, "bcma%d:%d", bus->num, core->core_index);
|
||||
- core->dev.parent = bcma_bus_get_host_dev(bus);
|
||||
- if (core->dev.parent)
|
||||
- bcma_of_fill_device(core->dev.parent, core);
|
||||
+ core->dev.parent = bus->dev;
|
||||
+ if (bus->dev)
|
||||
+ bcma_of_fill_device(bus->dev, core);
|
||||
|
||||
switch (bus->hosttype) {
|
||||
case BCMA_HOSTTYPE_PCI:
|
||||
- core->dma_dev = &bus->host_pci->dev;
|
||||
+ core->dma_dev = bus->dev;
|
||||
core->irq = bus->host_pci->irq;
|
||||
break;
|
||||
case BCMA_HOSTTYPE_SOC:
|
||||
- if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||
- core->dma_dev = &bus->host_pdev->dev;
|
||||
+ if (IS_ENABLED(CONFIG_OF) && bus->dev) {
|
||||
+ core->dma_dev = bus->dev;
|
||||
} else {
|
||||
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||
core->dma_dev = &core->dev;
|
||||
@@ -261,28 +261,6 @@ void bcma_prepare_core(struct bcma_bus *
|
||||
}
|
||||
}
|
||||
|
||||
-struct device *bcma_bus_get_host_dev(struct bcma_bus *bus)
|
||||
-{
|
||||
- switch (bus->hosttype) {
|
||||
- case BCMA_HOSTTYPE_PCI:
|
||||
- if (bus->host_pci)
|
||||
- return &bus->host_pci->dev;
|
||||
- else
|
||||
- return NULL;
|
||||
- case BCMA_HOSTTYPE_SOC:
|
||||
- if (bus->host_pdev)
|
||||
- return &bus->host_pdev->dev;
|
||||
- else
|
||||
- return NULL;
|
||||
- case BCMA_HOSTTYPE_SDIO:
|
||||
- if (bus->host_sdio)
|
||||
- return &bus->host_sdio->dev;
|
||||
- else
|
||||
- return NULL;
|
||||
- }
|
||||
- return NULL;
|
||||
-}
|
||||
-
|
||||
void bcma_init_bus(struct bcma_bus *bus)
|
||||
{
|
||||
mutex_lock(&bcma_buses_mutex);
|
||||
@@ -402,7 +380,6 @@ int bcma_bus_register(struct bcma_bus *b
|
||||
{
|
||||
int err;
|
||||
struct bcma_device *core;
|
||||
- struct device *dev;
|
||||
|
||||
/* Scan for devices (cores) */
|
||||
err = bcma_bus_scan(bus);
|
||||
@@ -425,10 +402,8 @@ int bcma_bus_register(struct bcma_bus *b
|
||||
bcma_core_pci_early_init(&bus->drv_pci[0]);
|
||||
}
|
||||
|
||||
- dev = bcma_bus_get_host_dev(bus);
|
||||
- if (dev) {
|
||||
- of_platform_default_populate(dev->of_node, NULL, dev);
|
||||
- }
|
||||
+ if (bus->dev)
|
||||
+ of_platform_default_populate(bus->dev->of_node, NULL, bus->dev);
|
||||
|
||||
/* Cores providing flash access go before SPROM init */
|
||||
list_for_each_entry(core, &bus->cores, list) {
|
||||
--- a/include/linux/bcma/bcma.h
|
||||
+++ b/include/linux/bcma/bcma.h
|
||||
@@ -332,6 +332,8 @@ extern int bcma_arch_register_fallback_s
|
||||
struct ssb_sprom *out));
|
||||
|
||||
struct bcma_bus {
|
||||
+ struct device *dev;
|
||||
+
|
||||
/* The MMIO area. */
|
||||
void __iomem *mmio;
|
||||
|
||||
@@ -339,14 +341,7 @@ struct bcma_bus {
|
||||
|
||||
enum bcma_hosttype hosttype;
|
||||
bool host_is_pcie2; /* Used for BCMA_HOSTTYPE_PCI only */
|
||||
- union {
|
||||
- /* Pointer to the PCI bus (only for BCMA_HOSTTYPE_PCI) */
|
||||
- struct pci_dev *host_pci;
|
||||
- /* Pointer to the SDIO device (only for BCMA_HOSTTYPE_SDIO) */
|
||||
- struct sdio_func *host_sdio;
|
||||
- /* Pointer to platform device (only for BCMA_HOSTTYPE_SOC) */
|
||||
- struct platform_device *host_pdev;
|
||||
- };
|
||||
+ struct pci_dev *host_pci; /* PCI bus pointer (BCMA_HOSTTYPE_PCI only) */
|
||||
|
||||
struct bcma_chipinfo chipinfo;
|
||||
|
@ -0,0 +1,36 @@
|
||||
From 777bc4801a6868fcbff09ffb6e30f023e7c5ed38 Mon Sep 17 00:00:00 2001
|
||||
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||
Date: Wed, 2 Jan 2019 00:00:02 +0100
|
||||
Subject: [PATCH] bcma: use dev_* printing functions
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
It provides more meaningful messages.
|
||||
|
||||
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||
Signed-off-by: Kalle Valo <kvalo@codeaurora.org>
|
||||
---
|
||||
drivers/bcma/bcma_private.h | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/bcma/bcma_private.h
|
||||
+++ b/drivers/bcma/bcma_private.h
|
||||
@@ -10,13 +10,13 @@
|
||||
#include <linux/delay.h>
|
||||
|
||||
#define bcma_err(bus, fmt, ...) \
|
||||
- pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
+ dev_err((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
#define bcma_warn(bus, fmt, ...) \
|
||||
- pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
+ dev_warn((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
#define bcma_info(bus, fmt, ...) \
|
||||
- pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
+ dev_info((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
#define bcma_debug(bus, fmt, ...) \
|
||||
- pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
+ dev_dbg((bus)->dev, "bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
|
||||
|
||||
struct bcma_bus;
|
||||
|
@ -0,0 +1,79 @@
|
||||
From 46bf067870156abd61fe24d14c2486d15b8b502c Mon Sep 17 00:00:00 2001
|
||||
From: Dave Taht <dave@taht.net>
|
||||
Date: Fri, 14 Dec 2018 18:38:40 +0000
|
||||
Subject: [PATCH 1/1] Allow class-e address assignment in ifconfig and early
|
||||
boot
|
||||
|
||||
While the linux kernel became mostly "class-e clean" a decade ago,
|
||||
and most distributions long ago switched to the iproute2 suite
|
||||
of utilities, which allow class-e (240.0.0.0/4) address assignment,
|
||||
distributions relying on busybox, toybox and other forms of
|
||||
ifconfig cannot assign class-e addresses without this kernel patch.
|
||||
|
||||
With this patch, also, a boot command line on these addresses is feasible:
|
||||
(ip=248.0.1.2::248.0.1.1:255.255.255.0).
|
||||
|
||||
While CIDR has been obsolete for 2 decades, and a survey of all the
|
||||
userspace open source code in the world shows most IN_whatever macros
|
||||
are also obsolete... rather than obsolete CIDR from this ioctl entirely,
|
||||
this patch merely enables class-e assignment, sanely.
|
||||
|
||||
H/T to Vince Fuller and his original patch here:
|
||||
https://lkml.org/lkml/2008/1/7/370
|
||||
|
||||
Signed-off-by: Dave Taht <dave.taht@gmail.com>
|
||||
Reviewed-by: John Gilmore <gnu@toad.com>
|
||||
---
|
||||
include/uapi/linux/in.h | 8 ++++++--
|
||||
net/ipv4/devinet.c | 4 +++-
|
||||
net/ipv4/ipconfig.c | 2 ++
|
||||
3 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/include/uapi/linux/in.h
|
||||
+++ b/include/uapi/linux/in.h
|
||||
@@ -268,8 +268,12 @@ struct sockaddr_in {
|
||||
#define IN_MULTICAST(a) IN_CLASSD(a)
|
||||
#define IN_MULTICAST_NET 0xF0000000
|
||||
|
||||
-#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
|
||||
-#define IN_BADCLASS(a) IN_EXPERIMENTAL((a))
|
||||
+#define IN_BADCLASS(a) (((long int) (a) ) == (long int)0xffffffff)
|
||||
+#define IN_EXPERIMENTAL(a) IN_BADCLASS((a))
|
||||
+
|
||||
+#define IN_CLASSE(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000)
|
||||
+#define IN_CLASSE_NET 0xffffffff
|
||||
+#define IN_CLASSE_NSHIFT 0
|
||||
|
||||
/* Address to accept any incoming messages. */
|
||||
#define INADDR_ANY ((unsigned long int) 0x00000000)
|
||||
--- a/net/ipv4/devinet.c
|
||||
+++ b/net/ipv4/devinet.c
|
||||
@@ -949,7 +949,7 @@ static int inet_abc_len(__be32 addr)
|
||||
{
|
||||
int rc = -1; /* Something else, probably a multicast. */
|
||||
|
||||
- if (ipv4_is_zeronet(addr))
|
||||
+ if (ipv4_is_zeronet(addr) || ipv4_is_lbcast(addr))
|
||||
rc = 0;
|
||||
else {
|
||||
__u32 haddr = ntohl(addr);
|
||||
@@ -960,6 +960,8 @@ static int inet_abc_len(__be32 addr)
|
||||
rc = 16;
|
||||
else if (IN_CLASSC(haddr))
|
||||
rc = 24;
|
||||
+ else if (IN_CLASSE(haddr))
|
||||
+ rc = 32;
|
||||
}
|
||||
|
||||
return rc;
|
||||
--- a/net/ipv4/ipconfig.c
|
||||
+++ b/net/ipv4/ipconfig.c
|
||||
@@ -429,6 +429,8 @@ static int __init ic_defaults(void)
|
||||
ic_netmask = htonl(IN_CLASSB_NET);
|
||||
else if (IN_CLASSC(ntohl(ic_myaddr)))
|
||||
ic_netmask = htonl(IN_CLASSC_NET);
|
||||
+ else if (IN_CLASSE(ntohl(ic_myaddr)))
|
||||
+ ic_netmask = htonl(IN_CLASSE_NET);
|
||||
else {
|
||||
pr_err("IP-Config: Unable to guess netmask for address %pI4\n",
|
||||
&ic_myaddr);
|
@ -0,0 +1,46 @@
|
||||
From 4cc30de79d293f1e8c5f50ae3a9c005def9564a0 Mon Sep 17 00:00:00 2001
|
||||
From: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
Date: Mon, 7 Jan 2019 14:14:27 +0100
|
||||
Subject: [PATCH 2/2] arm: cns3xxx: use actual size reads for PCIe
|
||||
|
||||
commit 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
reimplemented cns3xxx_pci_read_config() using pci_generic_config_read32(),
|
||||
which preserved the property of only doing 32-bit reads.
|
||||
|
||||
It also replaced cns3xxx_pci_write_config() with pci_generic_config_write(),
|
||||
so it changed writes from always being 32 bits to being the actual size,
|
||||
which works just fine.
|
||||
|
||||
Due to:
|
||||
- The documentation does not mention that only 32 bit access is allowed.
|
||||
- Writes are already executed using the actual size
|
||||
- Extensive testing shows that 8b, 16b and 32b reads work as intended
|
||||
|
||||
It makes perfectly sense to also swap 32 bit reading in favor of actual size.
|
||||
|
||||
Fixes: 802b7c06adc7 ("ARM: cns3xxx: Convert PCI to use generic config accessors")
|
||||
Suggested-by: Bjorn Helgaas <bhelgaas@google.com>
|
||||
Signed-off-by: Koen Vandeputte <koen.vandeputte@ncentric.com>
|
||||
CC: Arnd Bergmann <arnd@arndb.de>
|
||||
CC: Krzysztof Halasa <khalasa@piap.pl>
|
||||
CC: Olof Johansson <olof@lixom.net>
|
||||
CC: Robin Leblon <robin.leblon@ncentric.com>
|
||||
CC: Rob Herring <robh@kernel.org>
|
||||
CC: Russell King <linux@armlinux.org.uk>
|
||||
CC: Tim Harvey <tharvey@gateworks.com>
|
||||
CC: stable@vger.kernel.org # v4.0+
|
||||
---
|
||||
arch/arm/mach-cns3xxx/pcie.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
--- a/arch/arm/mach-cns3xxx/pcie.c
|
||||
+++ b/arch/arm/mach-cns3xxx/pcie.c
|
||||
@@ -93,7 +93,7 @@ static int cns3xxx_pci_read_config(struc
|
||||
u32 mask = (0x1ull << (size * 8)) - 1;
|
||||
int shift = (where % 4) * 8;
|
||||
|
||||
- ret = pci_generic_config_read32(bus, devfn, where, size, val);
|
||||
+ ret = pci_generic_config_read(bus, devfn, where, size, val);
|
||||
|
||||
if (ret == PCIBIOS_SUCCESSFUL && !bus->number && !devfn &&
|
||||
(where & 0xffc) == PCI_CLASS_REVISION)
|
@ -0,0 +1,63 @@
|
||||
From 28b5c129ca6e585ec95c160ec4297bc6c6360b6f Mon Sep 17 00:00:00 2001
|
||||
From: Minas Harutyunyan <minas.harutyunyan@synopsys.com>
|
||||
Date: Mon, 4 Mar 2019 17:08:07 +0400
|
||||
Subject: usb: dwc2: Set lpm mode parameters depend on HW configuration
|
||||
|
||||
If core not supported lpm, i.e. BCM2835 then confusing warnings seen
|
||||
in log.
|
||||
|
||||
To avoid these warnings, added function dwc2_set_param_lpm() to set
|
||||
lpm and other lpm related parameters based on lpm support by core.
|
||||
|
||||
Signed-off-by: Minas Harutyunyan <hminas@synopsys.com>
|
||||
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
|
||||
---
|
||||
drivers/usb/dwc2/params.c | 23 ++++++++++++++++++-----
|
||||
1 file changed, 18 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/usb/dwc2/params.c
|
||||
+++ b/drivers/usb/dwc2/params.c
|
||||
@@ -273,6 +273,23 @@ static void dwc2_set_param_power_down(st
|
||||
hsotg->params.power_down = val;
|
||||
}
|
||||
|
||||
+static void dwc2_set_param_lpm(struct dwc2_hsotg *hsotg)
|
||||
+{
|
||||
+ struct dwc2_core_params *p = &hsotg->params;
|
||||
+
|
||||
+ p->lpm = hsotg->hw_params.lpm_mode;
|
||||
+ if (p->lpm) {
|
||||
+ p->lpm_clock_gating = true;
|
||||
+ p->besl = true;
|
||||
+ p->hird_threshold_en = true;
|
||||
+ p->hird_threshold = 4;
|
||||
+ } else {
|
||||
+ p->lpm_clock_gating = false;
|
||||
+ p->besl = false;
|
||||
+ p->hird_threshold_en = false;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* dwc2_set_default_params() - Set all core parameters to their
|
||||
* auto-detected default values.
|
||||
@@ -291,6 +308,7 @@ static void dwc2_set_default_params(stru
|
||||
dwc2_set_param_speed(hsotg);
|
||||
dwc2_set_param_phy_utmi_width(hsotg);
|
||||
dwc2_set_param_power_down(hsotg);
|
||||
+ dwc2_set_param_lpm(hsotg);
|
||||
p->phy_ulpi_ddr = false;
|
||||
p->phy_ulpi_ext_vbus = false;
|
||||
|
||||
@@ -303,11 +321,6 @@ static void dwc2_set_default_params(stru
|
||||
p->reload_ctl = (hw->snpsid >= DWC2_CORE_REV_2_92a);
|
||||
p->uframe_sched = true;
|
||||
p->external_id_pin_ctl = false;
|
||||
- p->lpm = true;
|
||||
- p->lpm_clock_gating = true;
|
||||
- p->besl = true;
|
||||
- p->hird_threshold_en = true;
|
||||
- p->hird_threshold = 4;
|
||||
p->ipg_isoc_en = false;
|
||||
p->max_packet_count = hw->max_packet_count;
|
||||
p->max_transfer_size = hw->max_transfer_size;
|
@ -0,0 +1,280 @@
|
||||
From 9966a05c7b80f075f2bc7e48dbb108d3f2927234 Mon Sep 17 00:00:00 2001
|
||||
From: Dave Martin <Dave.Martin@arm.com>
|
||||
Date: Fri, 4 Jan 2019 13:09:51 +0000
|
||||
Subject: [PATCH] arm64/sve: Disentangle <uapi/asm/ptrace.h> from
|
||||
<uapi/asm/sigcontext.h>
|
||||
|
||||
Currently, <uapi/asm/sigcontext.h> provides common definitions for
|
||||
describing SVE context structures that are also used by the ptrace
|
||||
definitions in <uapi/asm/ptrace.h>.
|
||||
|
||||
For this reason, a #include of <asm/sigcontext.h> was added in
|
||||
ptrace.h, but it this turns out that this can interact badly with
|
||||
userspace code that tries to include ptrace.h on top of the libc
|
||||
headers (which may provide their own shadow definitions for
|
||||
sigcontext.h).
|
||||
|
||||
To make the headers easier for userspace to consume, this patch
|
||||
bounces the common definitions into an __SVE_* namespace and moves
|
||||
them to a backend header <uapi/asm/sve_context.h> that can be
|
||||
included by the other headers as appropriate. This should allow
|
||||
ptrace.h to be used alongside libc's sigcontext.h (if any) without
|
||||
ill effects.
|
||||
|
||||
This should make the situation unambiguous: <asm/sigcontext.h> is
|
||||
the header to include for the sigframe-specific definitions, while
|
||||
<asm/ptrace.h> is the header to include for ptrace-specific
|
||||
definitions.
|
||||
|
||||
To avoid conflicting with existing usage, <asm/sigcontext.h>
|
||||
remains the canonical way to get the common definitions for
|
||||
SVE_VQ_MIN, sve_vq_from_vl() etc., both in userspace and in the
|
||||
kernel: relying on these being defined as a side effect of
|
||||
including just <asm/ptrace.h> was never intended to be safe.
|
||||
|
||||
Signed-off-by: Dave Martin <Dave.Martin@arm.com>
|
||||
Signed-off-by: Will Deacon <will.deacon@arm.com>
|
||||
---
|
||||
arch/arm64/include/uapi/asm/ptrace.h | 39 ++++++++--------
|
||||
arch/arm64/include/uapi/asm/sigcontext.h | 56 +++++++++++------------
|
||||
arch/arm64/include/uapi/asm/sve_context.h | 53 +++++++++++++++++++++
|
||||
3 files changed, 99 insertions(+), 49 deletions(-)
|
||||
create mode 100644 arch/arm64/include/uapi/asm/sve_context.h
|
||||
|
||||
--- a/arch/arm64/include/uapi/asm/ptrace.h
|
||||
+++ b/arch/arm64/include/uapi/asm/ptrace.h
|
||||
@@ -23,7 +23,7 @@
|
||||
#include <linux/types.h>
|
||||
|
||||
#include <asm/hwcap.h>
|
||||
-#include <asm/sigcontext.h>
|
||||
+#include <asm/sve_context.h>
|
||||
|
||||
|
||||
/*
|
||||
@@ -129,9 +129,9 @@ struct user_sve_header {
|
||||
*/
|
||||
|
||||
/* Offset from the start of struct user_sve_header to the register data */
|
||||
-#define SVE_PT_REGS_OFFSET \
|
||||
- ((sizeof(struct user_sve_header) + (SVE_VQ_BYTES - 1)) \
|
||||
- / SVE_VQ_BYTES * SVE_VQ_BYTES)
|
||||
+#define SVE_PT_REGS_OFFSET \
|
||||
+ ((sizeof(struct user_sve_header) + (__SVE_VQ_BYTES - 1)) \
|
||||
+ / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
|
||||
|
||||
/*
|
||||
* The register data content and layout depends on the value of the
|
||||
@@ -177,39 +177,36 @@ struct user_sve_header {
|
||||
* Additional data might be appended in the future.
|
||||
*/
|
||||
|
||||
-#define SVE_PT_SVE_ZREG_SIZE(vq) SVE_SIG_ZREG_SIZE(vq)
|
||||
-#define SVE_PT_SVE_PREG_SIZE(vq) SVE_SIG_PREG_SIZE(vq)
|
||||
-#define SVE_PT_SVE_FFR_SIZE(vq) SVE_SIG_FFR_SIZE(vq)
|
||||
+#define SVE_PT_SVE_ZREG_SIZE(vq) __SVE_ZREG_SIZE(vq)
|
||||
+#define SVE_PT_SVE_PREG_SIZE(vq) __SVE_PREG_SIZE(vq)
|
||||
+#define SVE_PT_SVE_FFR_SIZE(vq) __SVE_FFR_SIZE(vq)
|
||||
#define SVE_PT_SVE_FPSR_SIZE sizeof(__u32)
|
||||
#define SVE_PT_SVE_FPCR_SIZE sizeof(__u32)
|
||||
|
||||
-#define __SVE_SIG_TO_PT(offset) \
|
||||
- ((offset) - SVE_SIG_REGS_OFFSET + SVE_PT_REGS_OFFSET)
|
||||
-
|
||||
#define SVE_PT_SVE_OFFSET SVE_PT_REGS_OFFSET
|
||||
|
||||
#define SVE_PT_SVE_ZREGS_OFFSET \
|
||||
- __SVE_SIG_TO_PT(SVE_SIG_ZREGS_OFFSET)
|
||||
+ (SVE_PT_REGS_OFFSET + __SVE_ZREGS_OFFSET)
|
||||
#define SVE_PT_SVE_ZREG_OFFSET(vq, n) \
|
||||
- __SVE_SIG_TO_PT(SVE_SIG_ZREG_OFFSET(vq, n))
|
||||
+ (SVE_PT_REGS_OFFSET + __SVE_ZREG_OFFSET(vq, n))
|
||||
#define SVE_PT_SVE_ZREGS_SIZE(vq) \
|
||||
- (SVE_PT_SVE_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
|
||||
+ (SVE_PT_SVE_ZREG_OFFSET(vq, __SVE_NUM_ZREGS) - SVE_PT_SVE_ZREGS_OFFSET)
|
||||
|
||||
#define SVE_PT_SVE_PREGS_OFFSET(vq) \
|
||||
- __SVE_SIG_TO_PT(SVE_SIG_PREGS_OFFSET(vq))
|
||||
+ (SVE_PT_REGS_OFFSET + __SVE_PREGS_OFFSET(vq))
|
||||
#define SVE_PT_SVE_PREG_OFFSET(vq, n) \
|
||||
- __SVE_SIG_TO_PT(SVE_SIG_PREG_OFFSET(vq, n))
|
||||
+ (SVE_PT_REGS_OFFSET + __SVE_PREG_OFFSET(vq, n))
|
||||
#define SVE_PT_SVE_PREGS_SIZE(vq) \
|
||||
- (SVE_PT_SVE_PREG_OFFSET(vq, SVE_NUM_PREGS) - \
|
||||
+ (SVE_PT_SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - \
|
||||
SVE_PT_SVE_PREGS_OFFSET(vq))
|
||||
|
||||
#define SVE_PT_SVE_FFR_OFFSET(vq) \
|
||||
- __SVE_SIG_TO_PT(SVE_SIG_FFR_OFFSET(vq))
|
||||
+ (SVE_PT_REGS_OFFSET + __SVE_FFR_OFFSET(vq))
|
||||
|
||||
#define SVE_PT_SVE_FPSR_OFFSET(vq) \
|
||||
((SVE_PT_SVE_FFR_OFFSET(vq) + SVE_PT_SVE_FFR_SIZE(vq) + \
|
||||
- (SVE_VQ_BYTES - 1)) \
|
||||
- / SVE_VQ_BYTES * SVE_VQ_BYTES)
|
||||
+ (__SVE_VQ_BYTES - 1)) \
|
||||
+ / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
|
||||
#define SVE_PT_SVE_FPCR_OFFSET(vq) \
|
||||
(SVE_PT_SVE_FPSR_OFFSET(vq) + SVE_PT_SVE_FPSR_SIZE)
|
||||
|
||||
@@ -220,8 +217,8 @@ struct user_sve_header {
|
||||
|
||||
#define SVE_PT_SVE_SIZE(vq, flags) \
|
||||
((SVE_PT_SVE_FPCR_OFFSET(vq) + SVE_PT_SVE_FPCR_SIZE \
|
||||
- - SVE_PT_SVE_OFFSET + (SVE_VQ_BYTES - 1)) \
|
||||
- / SVE_VQ_BYTES * SVE_VQ_BYTES)
|
||||
+ - SVE_PT_SVE_OFFSET + (__SVE_VQ_BYTES - 1)) \
|
||||
+ / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
|
||||
|
||||
#define SVE_PT_SIZE(vq, flags) \
|
||||
(((flags) & SVE_PT_REGS_MASK) == SVE_PT_REGS_SVE ? \
|
||||
--- a/arch/arm64/include/uapi/asm/sigcontext.h
|
||||
+++ b/arch/arm64/include/uapi/asm/sigcontext.h
|
||||
@@ -130,6 +130,8 @@ struct sve_context {
|
||||
|
||||
#endif /* !__ASSEMBLY__ */
|
||||
|
||||
+#include <asm/sve_context.h>
|
||||
+
|
||||
/*
|
||||
* The SVE architecture leaves space for future expansion of the
|
||||
* vector length beyond its initial architectural limit of 2048 bits
|
||||
@@ -138,21 +140,20 @@ struct sve_context {
|
||||
* See linux/Documentation/arm64/sve.txt for a description of the VL/VQ
|
||||
* terminology.
|
||||
*/
|
||||
-#define SVE_VQ_BYTES 16 /* number of bytes per quadword */
|
||||
+#define SVE_VQ_BYTES __SVE_VQ_BYTES /* bytes per quadword */
|
||||
|
||||
-#define SVE_VQ_MIN 1
|
||||
-#define SVE_VQ_MAX 512
|
||||
+#define SVE_VQ_MIN __SVE_VQ_MIN
|
||||
+#define SVE_VQ_MAX __SVE_VQ_MAX
|
||||
|
||||
-#define SVE_VL_MIN (SVE_VQ_MIN * SVE_VQ_BYTES)
|
||||
-#define SVE_VL_MAX (SVE_VQ_MAX * SVE_VQ_BYTES)
|
||||
+#define SVE_VL_MIN __SVE_VL_MIN
|
||||
+#define SVE_VL_MAX __SVE_VL_MAX
|
||||
|
||||
-#define SVE_NUM_ZREGS 32
|
||||
-#define SVE_NUM_PREGS 16
|
||||
+#define SVE_NUM_ZREGS __SVE_NUM_ZREGS
|
||||
+#define SVE_NUM_PREGS __SVE_NUM_PREGS
|
||||
|
||||
-#define sve_vl_valid(vl) \
|
||||
- ((vl) % SVE_VQ_BYTES == 0 && (vl) >= SVE_VL_MIN && (vl) <= SVE_VL_MAX)
|
||||
-#define sve_vq_from_vl(vl) ((vl) / SVE_VQ_BYTES)
|
||||
-#define sve_vl_from_vq(vq) ((vq) * SVE_VQ_BYTES)
|
||||
+#define sve_vl_valid(vl) __sve_vl_valid(vl)
|
||||
+#define sve_vq_from_vl(vl) __sve_vq_from_vl(vl)
|
||||
+#define sve_vl_from_vq(vq) __sve_vl_from_vq(vq)
|
||||
|
||||
/*
|
||||
* If the SVE registers are currently live for the thread at signal delivery,
|
||||
@@ -205,34 +206,33 @@ struct sve_context {
|
||||
* Additional data might be appended in the future.
|
||||
*/
|
||||
|
||||
-#define SVE_SIG_ZREG_SIZE(vq) ((__u32)(vq) * SVE_VQ_BYTES)
|
||||
-#define SVE_SIG_PREG_SIZE(vq) ((__u32)(vq) * (SVE_VQ_BYTES / 8))
|
||||
-#define SVE_SIG_FFR_SIZE(vq) SVE_SIG_PREG_SIZE(vq)
|
||||
+#define SVE_SIG_ZREG_SIZE(vq) __SVE_ZREG_SIZE(vq)
|
||||
+#define SVE_SIG_PREG_SIZE(vq) __SVE_PREG_SIZE(vq)
|
||||
+#define SVE_SIG_FFR_SIZE(vq) __SVE_FFR_SIZE(vq)
|
||||
|
||||
#define SVE_SIG_REGS_OFFSET \
|
||||
- ((sizeof(struct sve_context) + (SVE_VQ_BYTES - 1)) \
|
||||
- / SVE_VQ_BYTES * SVE_VQ_BYTES)
|
||||
+ ((sizeof(struct sve_context) + (__SVE_VQ_BYTES - 1)) \
|
||||
+ / __SVE_VQ_BYTES * __SVE_VQ_BYTES)
|
||||
|
||||
-#define SVE_SIG_ZREGS_OFFSET SVE_SIG_REGS_OFFSET
|
||||
+#define SVE_SIG_ZREGS_OFFSET \
|
||||
+ (SVE_SIG_REGS_OFFSET + __SVE_ZREGS_OFFSET)
|
||||
#define SVE_SIG_ZREG_OFFSET(vq, n) \
|
||||
- (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREG_SIZE(vq) * (n))
|
||||
-#define SVE_SIG_ZREGS_SIZE(vq) \
|
||||
- (SVE_SIG_ZREG_OFFSET(vq, SVE_NUM_ZREGS) - SVE_SIG_ZREGS_OFFSET)
|
||||
+ (SVE_SIG_REGS_OFFSET + __SVE_ZREG_OFFSET(vq, n))
|
||||
+#define SVE_SIG_ZREGS_SIZE(vq) __SVE_ZREGS_SIZE(vq)
|
||||
|
||||
#define SVE_SIG_PREGS_OFFSET(vq) \
|
||||
- (SVE_SIG_ZREGS_OFFSET + SVE_SIG_ZREGS_SIZE(vq))
|
||||
+ (SVE_SIG_REGS_OFFSET + __SVE_PREGS_OFFSET(vq))
|
||||
#define SVE_SIG_PREG_OFFSET(vq, n) \
|
||||
- (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREG_SIZE(vq) * (n))
|
||||
-#define SVE_SIG_PREGS_SIZE(vq) \
|
||||
- (SVE_SIG_PREG_OFFSET(vq, SVE_NUM_PREGS) - SVE_SIG_PREGS_OFFSET(vq))
|
||||
+ (SVE_SIG_REGS_OFFSET + __SVE_PREG_OFFSET(vq, n))
|
||||
+#define SVE_SIG_PREGS_SIZE(vq) __SVE_PREGS_SIZE(vq)
|
||||
|
||||
#define SVE_SIG_FFR_OFFSET(vq) \
|
||||
- (SVE_SIG_PREGS_OFFSET(vq) + SVE_SIG_PREGS_SIZE(vq))
|
||||
+ (SVE_SIG_REGS_OFFSET + __SVE_FFR_OFFSET(vq))
|
||||
|
||||
#define SVE_SIG_REGS_SIZE(vq) \
|
||||
- (SVE_SIG_FFR_OFFSET(vq) + SVE_SIG_FFR_SIZE(vq) - SVE_SIG_REGS_OFFSET)
|
||||
-
|
||||
-#define SVE_SIG_CONTEXT_SIZE(vq) (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
|
||||
+ (__SVE_FFR_OFFSET(vq) + __SVE_FFR_SIZE(vq))
|
||||
|
||||
+#define SVE_SIG_CONTEXT_SIZE(vq) \
|
||||
+ (SVE_SIG_REGS_OFFSET + SVE_SIG_REGS_SIZE(vq))
|
||||
|
||||
#endif /* _UAPI__ASM_SIGCONTEXT_H */
|
||||
--- /dev/null
|
||||
+++ b/arch/arm64/include/uapi/asm/sve_context.h
|
||||
@@ -0,0 +1,53 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
+/* Copyright (C) 2017-2018 ARM Limited */
|
||||
+
|
||||
+/*
|
||||
+ * For use by other UAPI headers only.
|
||||
+ * Do not make direct use of header or its definitions.
|
||||
+ */
|
||||
+
|
||||
+#ifndef _UAPI__ASM_SVE_CONTEXT_H
|
||||
+#define _UAPI__ASM_SVE_CONTEXT_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+
|
||||
+#define __SVE_VQ_BYTES 16 /* number of bytes per quadword */
|
||||
+
|
||||
+#define __SVE_VQ_MIN 1
|
||||
+#define __SVE_VQ_MAX 512
|
||||
+
|
||||
+#define __SVE_VL_MIN (__SVE_VQ_MIN * __SVE_VQ_BYTES)
|
||||
+#define __SVE_VL_MAX (__SVE_VQ_MAX * __SVE_VQ_BYTES)
|
||||
+
|
||||
+#define __SVE_NUM_ZREGS 32
|
||||
+#define __SVE_NUM_PREGS 16
|
||||
+
|
||||
+#define __sve_vl_valid(vl) \
|
||||
+ ((vl) % __SVE_VQ_BYTES == 0 && \
|
||||
+ (vl) >= __SVE_VL_MIN && \
|
||||
+ (vl) <= __SVE_VL_MAX)
|
||||
+
|
||||
+#define __sve_vq_from_vl(vl) ((vl) / __SVE_VQ_BYTES)
|
||||
+#define __sve_vl_from_vq(vq) ((vq) * __SVE_VQ_BYTES)
|
||||
+
|
||||
+#define __SVE_ZREG_SIZE(vq) ((__u32)(vq) * __SVE_VQ_BYTES)
|
||||
+#define __SVE_PREG_SIZE(vq) ((__u32)(vq) * (__SVE_VQ_BYTES / 8))
|
||||
+#define __SVE_FFR_SIZE(vq) __SVE_PREG_SIZE(vq)
|
||||
+
|
||||
+#define __SVE_ZREGS_OFFSET 0
|
||||
+#define __SVE_ZREG_OFFSET(vq, n) \
|
||||
+ (__SVE_ZREGS_OFFSET + __SVE_ZREG_SIZE(vq) * (n))
|
||||
+#define __SVE_ZREGS_SIZE(vq) \
|
||||
+ (__SVE_ZREG_OFFSET(vq, __SVE_NUM_ZREGS) - __SVE_ZREGS_OFFSET)
|
||||
+
|
||||
+#define __SVE_PREGS_OFFSET(vq) \
|
||||
+ (__SVE_ZREGS_OFFSET + __SVE_ZREGS_SIZE(vq))
|
||||
+#define __SVE_PREG_OFFSET(vq, n) \
|
||||
+ (__SVE_PREGS_OFFSET(vq) + __SVE_PREG_SIZE(vq) * (n))
|
||||
+#define __SVE_PREGS_SIZE(vq) \
|
||||
+ (__SVE_PREG_OFFSET(vq, __SVE_NUM_PREGS) - __SVE_PREGS_OFFSET(vq))
|
||||
+
|
||||
+#define __SVE_FFR_OFFSET(vq) \
|
||||
+ (__SVE_PREGS_OFFSET(vq) + __SVE_PREGS_SIZE(vq))
|
||||
+
|
||||
+#endif /* ! _UAPI__ASM_SVE_CONTEXT_H */
|
@ -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
|
||||
@@ -535,5 +535,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_net(dev), 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
|
||||
@@ -216,47 +216,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_net(dev), 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,112 @@
|
||||
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
|
||||
@@ -1178,18 +1178,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);
|
||||
@@ -1226,10 +1214,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
|
||||
@@ -183,10 +183,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,
|
||||
@@ -317,6 +336,8 @@ static int nf_flow_offload_gc_step(struc
|
||||
rhashtable_walk_start(&hti);
|
||||
|
||||
while ((tuplehash = rhashtable_walk_next(&hti))) {
|
||||
+ bool teardown;
|
||||
+
|
||||
if (IS_ERR(tuplehash)) {
|
||||
err = PTR_ERR(tuplehash);
|
||||
if (err != -EAGAIN)
|
||||
@@ -329,9 +350,13 @@ static int nf_flow_offload_gc_step(struc
|
||||
|
||||
flow = container_of(tuplehash, struct flow_offload, tuplehash[0]);
|
||||
|
||||
- if (nf_flow_has_expired(flow) ||
|
||||
- (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);
|
||||
}
|
||||
out:
|
@ -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
|
||||
@@ -243,6 +243,9 @@ static void flow_offload_del(struct nf_f
|
||||
e = container_of(flow, struct flow_offload_entry, flow);
|
||||
clear_bit(IPS_OFFLOAD_BIT, &e->ct->status);
|
||||
|
||||
+ if (!(flow->flags & FLOW_OFFLOAD_TEARDOWN))
|
||||
+ flow_offload_fixup_ct_state(e->ct);
|
||||
+
|
||||
flow_offload_free(flow);
|
||||
}
|
||||
|
@ -0,0 +1,670 @@
|
||||
From d129a72f465dab2d9fc8f1580c38600a8b808327 Mon Sep 17 00:00:00 2001
|
||||
From: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Date: Wed, 13 Mar 2019 20:54:49 +0000
|
||||
Subject: [PATCH] net: sched: Backport Introduce act_ctinfo action
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
ctinfo is a new tc filter action module. It is designed to restore
|
||||
information contained in firewall conntrack marks to other packet fields
|
||||
and is typically used on packet ingress paths. At present it has two
|
||||
independent sub-functions or operating modes, DSCP restoration mode &
|
||||
skb mark restoration mode.
|
||||
|
||||
The DSCP restore mode:
|
||||
|
||||
This mode copies DSCP values that have been placed in the firewall
|
||||
conntrack mark back into the IPv4/v6 diffserv fields of relevant
|
||||
packets.
|
||||
|
||||
The DSCP restoration is intended for use and has been found useful for
|
||||
restoring ingress classifications based on egress classifications across
|
||||
links that bleach or otherwise change DSCP, typically home ISP Internet
|
||||
links. Restoring DSCP on ingress on the WAN link allows qdiscs such as
|
||||
but by no means limited to CAKE to shape inbound packets according to
|
||||
policies that are easier to set & mark on egress.
|
||||
|
||||
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. Thus marking the connection in some
|
||||
manner on egress for later restoration of classification on ingress is
|
||||
easier to implement.
|
||||
|
||||
Parameters related to DSCP restore mode:
|
||||
|
||||
dscpmask - a 32 bit mask of 6 contiguous bits and indicate bits of the
|
||||
conntrack mark field contain the DSCP value to be restored.
|
||||
|
||||
statemask - a 32 bit mask of (usually) 1 bit length, outside the area
|
||||
specified by dscpmask. This represents a conditional operation flag
|
||||
whereby the DSCP is only restored if the flag is set. 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 mask of zero disables the
|
||||
conditional behaviour ie. the conntrack mark DSCP bits are always
|
||||
restored to the ip diffserv field (assuming the conntrack entry is found
|
||||
& the skb is an ipv4/ipv6 type)
|
||||
|
||||
e.g. dscpmask 0xfc000000 statemask 0x01000000
|
||||
|
||||
|----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 |
|
||||
|-------------|
|
||||
|
||||
The skb mark restore mode (cpmark):
|
||||
|
||||
This mode copies the firewall conntrack mark to the skb's mark field.
|
||||
It is completely the functional equivalent of the existing act_connmark
|
||||
action with the additional feature of being able to apply a mask to the
|
||||
restored value.
|
||||
|
||||
Parameters related to skb mark restore mode:
|
||||
|
||||
mask - a 32 bit mask applied to the firewall conntrack mark to mask out
|
||||
bits unwanted for restoration. This can be useful where the conntrack
|
||||
mark is being used for different purposes by different applications. If
|
||||
not specified and by default the whole mark field is copied (i.e.
|
||||
default mask of 0xffffffff)
|
||||
|
||||
e.g. mask 0x00ffffff to mask out the top 8 bits being used by the
|
||||
aforementioned DSCP restore mode.
|
||||
|
||||
|----0x00----conntrack mark----ffffff---|
|
||||
| Bits 31-24 | |
|
||||
| DSCP & flag| some value here |
|
||||
|---------------------------------------|
|
||||
|
|
||||
|
|
||||
v
|
||||
|------------skb mark-------------------|
|
||||
| | |
|
||||
| zeroed | |
|
||||
|---------------------------------------|
|
||||
|
||||
Overall parameters:
|
||||
|
||||
zone - conntrack zone
|
||||
|
||||
control - action related control (reclassify | pipe | drop | continue |
|
||||
ok | goto chain <CHAIN_INDEX>)
|
||||
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
Reviewed-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Acked-by: Cong Wang <xiyou.wangcong@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
|
||||
Backport
|
||||
Signed-off-by: Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
---
|
||||
include/net/tc_act/tc_ctinfo.h | 33 ++
|
||||
include/uapi/linux/pkt_cls.h | 3 +-
|
||||
include/uapi/linux/tc_act/tc_ctinfo.h | 29 ++
|
||||
net/sched/Kconfig | 17 +
|
||||
net/sched/Makefile | 1 +
|
||||
net/sched/act_ctinfo.c | 420 ++++++++++++++++++++++
|
||||
tools/testing/selftests/tc-testing/config | 1 +
|
||||
7 files changed, 503 insertions(+), 1 deletion(-)
|
||||
create mode 100644 include/net/tc_act/tc_ctinfo.h
|
||||
create mode 100644 include/uapi/linux/tc_act/tc_ctinfo.h
|
||||
create mode 100644 net/sched/act_ctinfo.c
|
||||
|
||||
--- /dev/null
|
||||
+++ b/include/net/tc_act/tc_ctinfo.h
|
||||
@@ -0,0 +1,33 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 */
|
||||
+#ifndef __NET_TC_CTINFO_H
|
||||
+#define __NET_TC_CTINFO_H
|
||||
+
|
||||
+#include <net/act_api.h>
|
||||
+
|
||||
+struct tcf_ctinfo_params {
|
||||
+ struct rcu_head rcu;
|
||||
+ struct net *net;
|
||||
+ u32 dscpmask;
|
||||
+ u32 dscpstatemask;
|
||||
+ u32 cpmarkmask;
|
||||
+ u16 zone;
|
||||
+ u8 mode;
|
||||
+ u8 dscpmaskshift;
|
||||
+};
|
||||
+
|
||||
+struct tcf_ctinfo {
|
||||
+ struct tc_action common;
|
||||
+ struct tcf_ctinfo_params __rcu *params;
|
||||
+ u64 stats_dscp_set;
|
||||
+ u64 stats_dscp_error;
|
||||
+ u64 stats_cpmark_set;
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ CTINFO_MODE_DSCP = BIT(0),
|
||||
+ CTINFO_MODE_CPMARK = BIT(1)
|
||||
+};
|
||||
+
|
||||
+#define to_ctinfo(a) ((struct tcf_ctinfo *)a)
|
||||
+
|
||||
+#endif /* __NET_TC_CTINFO_H */
|
||||
--- a/include/uapi/linux/pkt_cls.h
|
||||
+++ b/include/uapi/linux/pkt_cls.h
|
||||
@@ -68,7 +68,8 @@ enum {
|
||||
TCA_ID_UNSPEC=0,
|
||||
TCA_ID_POLICE=1,
|
||||
/* other actions go here */
|
||||
- __TCA_ID_MAX=255
|
||||
+ TCA_ID_CTINFO,
|
||||
+ __TCA_ID_MAX = 255
|
||||
};
|
||||
|
||||
#define TCA_ID_MAX __TCA_ID_MAX
|
||||
--- /dev/null
|
||||
+++ b/include/uapi/linux/tc_act/tc_ctinfo.h
|
||||
@@ -0,0 +1,29 @@
|
||||
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
|
||||
+#ifndef __UAPI_TC_CTINFO_H
|
||||
+#define __UAPI_TC_CTINFO_H
|
||||
+
|
||||
+#include <linux/types.h>
|
||||
+#include <linux/pkt_cls.h>
|
||||
+
|
||||
+struct tc_ctinfo {
|
||||
+ tc_gen;
|
||||
+};
|
||||
+
|
||||
+enum {
|
||||
+ TCA_CTINFO_UNSPEC,
|
||||
+ TCA_CTINFO_PAD,
|
||||
+ TCA_CTINFO_TM,
|
||||
+ TCA_CTINFO_ACT,
|
||||
+ TCA_CTINFO_ZONE,
|
||||
+ TCA_CTINFO_PARMS_DSCP_MASK,
|
||||
+ TCA_CTINFO_PARMS_DSCP_STATEMASK,
|
||||
+ TCA_CTINFO_PARMS_CPMARK_MASK,
|
||||
+ TCA_CTINFO_STATS_DSCP_SET,
|
||||
+ TCA_CTINFO_STATS_DSCP_ERROR,
|
||||
+ TCA_CTINFO_STATS_CPMARK_SET,
|
||||
+ __TCA_CTINFO_MAX
|
||||
+};
|
||||
+
|
||||
+#define TCA_CTINFO_MAX (__TCA_CTINFO_MAX - 1)
|
||||
+
|
||||
+#endif
|
||||
--- a/net/sched/Kconfig
|
||||
+++ b/net/sched/Kconfig
|
||||
@@ -866,6 +866,23 @@ config NET_ACT_CONNMARK
|
||||
To compile this code as a module, choose M here: the
|
||||
module will be called act_connmark.
|
||||
|
||||
+config NET_ACT_CTINFO
|
||||
+ tristate "Netfilter Connection Mark Actions"
|
||||
+ depends on NET_CLS_ACT && NETFILTER && IP_NF_IPTABLES
|
||||
+ depends on NF_CONNTRACK && NF_CONNTRACK_MARK
|
||||
+ help
|
||||
+ Say Y here to allow transfer of a connmark stored information.
|
||||
+ Current actions transfer connmark stored DSCP into
|
||||
+ ipv4/v6 diffserv and/or to transfer connmark to packet
|
||||
+ mark. Both are useful for restoring egress based marks
|
||||
+ back onto ingress connections for qdisc priority mapping
|
||||
+ purposes.
|
||||
+
|
||||
+ If unsure, say N.
|
||||
+
|
||||
+ To compile this code as a module, choose M here: the
|
||||
+ module will be called act_ctinfo.
|
||||
+
|
||||
config NET_ACT_SKBMOD
|
||||
tristate "skb data modification action"
|
||||
depends on NET_CLS_ACT
|
||||
--- a/net/sched/Makefile
|
||||
+++ b/net/sched/Makefile
|
||||
@@ -21,6 +21,7 @@ obj-$(CONFIG_NET_ACT_CSUM) += act_csum.o
|
||||
obj-$(CONFIG_NET_ACT_VLAN) += act_vlan.o
|
||||
obj-$(CONFIG_NET_ACT_BPF) += act_bpf.o
|
||||
obj-$(CONFIG_NET_ACT_CONNMARK) += act_connmark.o
|
||||
+obj-$(CONFIG_NET_ACT_CTINFO) += act_ctinfo.o
|
||||
obj-$(CONFIG_NET_ACT_SKBMOD) += act_skbmod.o
|
||||
obj-$(CONFIG_NET_ACT_IFE) += act_ife.o
|
||||
obj-$(CONFIG_NET_IFE_SKBMARK) += act_meta_mark.o
|
||||
--- /dev/null
|
||||
+++ b/net/sched/act_ctinfo.c
|
||||
@@ -0,0 +1,420 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+/* net/sched/act_ctinfo.c netfilter ctinfo connmark actions
|
||||
+ *
|
||||
+ * Copyright (c) 2019 Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/module.h>
|
||||
+#include <linux/init.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/skbuff.h>
|
||||
+#include <linux/rtnetlink.h>
|
||||
+#include <linux/pkt_cls.h>
|
||||
+#include <linux/ip.h>
|
||||
+#include <linux/ipv6.h>
|
||||
+#include <net/netlink.h>
|
||||
+#include <net/pkt_sched.h>
|
||||
+#include <net/act_api.h>
|
||||
+#include <net/pkt_cls.h>
|
||||
+#include <uapi/linux/tc_act/tc_ctinfo.h>
|
||||
+#include <net/tc_act/tc_ctinfo.h>
|
||||
+
|
||||
+#include <net/netfilter/nf_conntrack.h>
|
||||
+#include <net/netfilter/nf_conntrack_core.h>
|
||||
+#include <net/netfilter/nf_conntrack_ecache.h>
|
||||
+#include <net/netfilter/nf_conntrack_zones.h>
|
||||
+
|
||||
+static struct tc_action_ops act_ctinfo_ops;
|
||||
+static unsigned int ctinfo_net_id;
|
||||
+
|
||||
+static void tcf_ctinfo_dscp_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
|
||||
+ struct tcf_ctinfo_params *cp,
|
||||
+ struct sk_buff *skb, int wlen, int proto)
|
||||
+{
|
||||
+ u8 dscp, newdscp;
|
||||
+
|
||||
+ newdscp = (((ct->mark & cp->dscpmask) >> cp->dscpmaskshift) << 2) &
|
||||
+ ~INET_ECN_MASK;
|
||||
+
|
||||
+ switch (proto) {
|
||||
+ case NFPROTO_IPV4:
|
||||
+ dscp = ipv4_get_dsfield(ip_hdr(skb)) & ~INET_ECN_MASK;
|
||||
+ if (dscp != newdscp) {
|
||||
+ if (likely(!skb_try_make_writable(skb, wlen))) {
|
||||
+ ipv4_change_dsfield(ip_hdr(skb),
|
||||
+ INET_ECN_MASK,
|
||||
+ newdscp);
|
||||
+ ca->stats_dscp_set++;
|
||||
+ } else {
|
||||
+ ca->stats_dscp_error++;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+ case NFPROTO_IPV6:
|
||||
+ dscp = ipv6_get_dsfield(ipv6_hdr(skb)) & ~INET_ECN_MASK;
|
||||
+ if (dscp != newdscp) {
|
||||
+ if (likely(!skb_try_make_writable(skb, wlen))) {
|
||||
+ ipv6_change_dsfield(ipv6_hdr(skb),
|
||||
+ INET_ECN_MASK,
|
||||
+ newdscp);
|
||||
+ ca->stats_dscp_set++;
|
||||
+ } else {
|
||||
+ ca->stats_dscp_error++;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void tcf_ctinfo_cpmark_set(struct nf_conn *ct, struct tcf_ctinfo *ca,
|
||||
+ struct tcf_ctinfo_params *cp,
|
||||
+ struct sk_buff *skb)
|
||||
+{
|
||||
+ ca->stats_cpmark_set++;
|
||||
+ skb->mark = ct->mark & cp->cpmarkmask;
|
||||
+}
|
||||
+
|
||||
+static int tcf_ctinfo_act(struct sk_buff *skb, const struct tc_action *a,
|
||||
+ struct tcf_result *res)
|
||||
+{
|
||||
+ const struct nf_conntrack_tuple_hash *thash = NULL;
|
||||
+ struct tcf_ctinfo *ca = to_ctinfo(a);
|
||||
+ struct nf_conntrack_tuple tuple;
|
||||
+ struct nf_conntrack_zone zone;
|
||||
+ enum ip_conntrack_info ctinfo;
|
||||
+ struct tcf_ctinfo_params *cp;
|
||||
+ struct nf_conn *ct;
|
||||
+ int proto, wlen;
|
||||
+ int action;
|
||||
+
|
||||
+ cp = rcu_dereference_bh(ca->params);
|
||||
+
|
||||
+ tcf_lastuse_update(&ca->tcf_tm);
|
||||
+ bstats_update(&ca->tcf_bstats, skb);
|
||||
+ action = READ_ONCE(ca->tcf_action);
|
||||
+
|
||||
+ wlen = skb_network_offset(skb);
|
||||
+ if (tc_skb_protocol(skb) == htons(ETH_P_IP)) {
|
||||
+ wlen += sizeof(struct iphdr);
|
||||
+ if (!pskb_may_pull(skb, wlen))
|
||||
+ goto out;
|
||||
+
|
||||
+ proto = NFPROTO_IPV4;
|
||||
+ } else if (tc_skb_protocol(skb) == htons(ETH_P_IPV6)) {
|
||||
+ wlen += sizeof(struct ipv6hdr);
|
||||
+ if (!pskb_may_pull(skb, wlen))
|
||||
+ goto out;
|
||||
+
|
||||
+ proto = NFPROTO_IPV6;
|
||||
+ } else {
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
+ ct = nf_ct_get(skb, &ctinfo);
|
||||
+ if (!ct) { /* look harder, usually ingress */
|
||||
+ if (!nf_ct_get_tuplepr(skb, skb_network_offset(skb),
|
||||
+ proto, cp->net, &tuple))
|
||||
+ goto out;
|
||||
+ zone.id = cp->zone;
|
||||
+ zone.dir = NF_CT_DEFAULT_ZONE_DIR;
|
||||
+
|
||||
+ thash = nf_conntrack_find_get(cp->net, &zone, &tuple);
|
||||
+ if (!thash)
|
||||
+ goto out;
|
||||
+
|
||||
+ ct = nf_ct_tuplehash_to_ctrack(thash);
|
||||
+ }
|
||||
+
|
||||
+ if (cp->mode & CTINFO_MODE_DSCP)
|
||||
+ if (!cp->dscpstatemask || (ct->mark & cp->dscpstatemask))
|
||||
+ tcf_ctinfo_dscp_set(ct, ca, cp, skb, wlen, proto);
|
||||
+
|
||||
+ if (cp->mode & CTINFO_MODE_CPMARK)
|
||||
+ tcf_ctinfo_cpmark_set(ct, ca, cp, skb);
|
||||
+
|
||||
+ if (thash)
|
||||
+ nf_ct_put(ct);
|
||||
+out:
|
||||
+ return action;
|
||||
+}
|
||||
+
|
||||
+static const struct nla_policy ctinfo_policy[TCA_CTINFO_MAX + 1] = {
|
||||
+ [TCA_CTINFO_ACT] = { .len = sizeof(struct
|
||||
+ tc_ctinfo) },
|
||||
+ [TCA_CTINFO_ZONE] = { .type = NLA_U16 },
|
||||
+ [TCA_CTINFO_PARMS_DSCP_MASK] = { .type = NLA_U32 },
|
||||
+ [TCA_CTINFO_PARMS_DSCP_STATEMASK] = { .type = NLA_U32 },
|
||||
+ [TCA_CTINFO_PARMS_CPMARK_MASK] = { .type = NLA_U32 },
|
||||
+};
|
||||
+
|
||||
+static int tcf_ctinfo_init(struct net *net, struct nlattr *nla,
|
||||
+ struct nlattr *est, struct tc_action **a,
|
||||
+ int ovr, int bind, bool rtnl_held,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
|
||||
+ u32 dscpmask = 0, dscpstatemask, index;
|
||||
+ struct nlattr *tb[TCA_CTINFO_MAX + 1];
|
||||
+ struct tcf_ctinfo_params *cp_new;
|
||||
+/* struct tcf_chain *goto_ch = NULL; */
|
||||
+ struct tc_ctinfo *actparm;
|
||||
+ struct tcf_ctinfo *ci;
|
||||
+ u8 dscpmaskshift;
|
||||
+ int ret = 0, err;
|
||||
+
|
||||
+ if (!nla) {
|
||||
+ NL_SET_ERR_MSG_MOD(extack, "ctinfo requires attributes to be passed");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+
|
||||
+ err = nla_parse_nested(tb, TCA_CTINFO_MAX, nla, ctinfo_policy, extack);
|
||||
+ if (err < 0)
|
||||
+ return err;
|
||||
+
|
||||
+ if (!tb[TCA_CTINFO_ACT]) {
|
||||
+ NL_SET_ERR_MSG_MOD(extack,
|
||||
+ "Missing required TCA_CTINFO_ACT attribute");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ actparm = nla_data(tb[TCA_CTINFO_ACT]);
|
||||
+
|
||||
+ /* do some basic validation here before dynamically allocating things */
|
||||
+ /* that we would otherwise have to clean up. */
|
||||
+ if (tb[TCA_CTINFO_PARMS_DSCP_MASK]) {
|
||||
+ dscpmask = nla_get_u32(tb[TCA_CTINFO_PARMS_DSCP_MASK]);
|
||||
+ /* need contiguous 6 bit mask */
|
||||
+ dscpmaskshift = dscpmask ? __ffs(dscpmask) : 0;
|
||||
+ if ((~0 & (dscpmask >> dscpmaskshift)) != 0x3f) {
|
||||
+ NL_SET_ERR_MSG_ATTR(extack,
|
||||
+ tb[TCA_CTINFO_PARMS_DSCP_MASK],
|
||||
+ "dscp mask must be 6 contiguous bits");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ dscpstatemask = tb[TCA_CTINFO_PARMS_DSCP_STATEMASK] ?
|
||||
+ nla_get_u32(tb[TCA_CTINFO_PARMS_DSCP_STATEMASK]) : 0;
|
||||
+ /* mask & statemask must not overlap */
|
||||
+ if (dscpmask & dscpstatemask) {
|
||||
+ NL_SET_ERR_MSG_ATTR(extack,
|
||||
+ tb[TCA_CTINFO_PARMS_DSCP_STATEMASK],
|
||||
+ "dscp statemask must not overlap dscp mask");
|
||||
+ return -EINVAL;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ /* done the validation:now to the actual action allocation */
|
||||
+ index = actparm->index;
|
||||
+ err = tcf_idr_check_alloc(tn, &index, a, bind);
|
||||
+ if (!err) {
|
||||
+ ret = tcf_idr_create(tn, index, est, a,
|
||||
+ &act_ctinfo_ops, bind, false);
|
||||
+ if (ret) {
|
||||
+ tcf_idr_cleanup(tn, index);
|
||||
+ return ret;
|
||||
+ }
|
||||
+ ret = ACT_P_CREATED;
|
||||
+ } else if (err > 0) {
|
||||
+ if (bind) /* don't override defaults */
|
||||
+ return 0;
|
||||
+ if (!ovr) {
|
||||
+ tcf_idr_release(*a, bind);
|
||||
+ return -EEXIST;
|
||||
+ }
|
||||
+ } else {
|
||||
+ return err;
|
||||
+ }
|
||||
+
|
||||
+/* err = tcf_action_check_ctrlact(actparm->action, tp, &goto_ch, extack);
|
||||
+ if (err < 0)
|
||||
+ goto release_idr;
|
||||
+ */
|
||||
+
|
||||
+ ci = to_ctinfo(*a);
|
||||
+
|
||||
+ cp_new = kzalloc(sizeof(*cp_new), GFP_KERNEL);
|
||||
+ if (unlikely(!cp_new)) {
|
||||
+ err = -ENOMEM;
|
||||
+ goto put_chain;
|
||||
+ }
|
||||
+
|
||||
+ cp_new->net = net;
|
||||
+ cp_new->zone = tb[TCA_CTINFO_ZONE] ?
|
||||
+ nla_get_u16(tb[TCA_CTINFO_ZONE]) : 0;
|
||||
+ if (dscpmask) {
|
||||
+ cp_new->dscpmask = dscpmask;
|
||||
+ cp_new->dscpmaskshift = dscpmaskshift;
|
||||
+ cp_new->dscpstatemask = dscpstatemask;
|
||||
+ cp_new->mode |= CTINFO_MODE_DSCP;
|
||||
+ }
|
||||
+
|
||||
+ if (tb[TCA_CTINFO_PARMS_CPMARK_MASK]) {
|
||||
+ cp_new->cpmarkmask =
|
||||
+ nla_get_u32(tb[TCA_CTINFO_PARMS_CPMARK_MASK]);
|
||||
+ cp_new->mode |= CTINFO_MODE_CPMARK;
|
||||
+ }
|
||||
+
|
||||
+ spin_lock_bh(&ci->tcf_lock);
|
||||
+/* goto_ch = tcf_action_set_ctrlact(*a, actparm->action, goto_ch); */
|
||||
+ ci->tcf_action = actparm->action;
|
||||
+ rcu_swap_protected(ci->params, cp_new,
|
||||
+ lockdep_is_held(&ci->tcf_lock));
|
||||
+ spin_unlock_bh(&ci->tcf_lock);
|
||||
+
|
||||
+/* if (goto_ch)
|
||||
+ tcf_chain_put_by_act(goto_ch); */
|
||||
+ if (cp_new)
|
||||
+ kfree_rcu(cp_new, rcu);
|
||||
+
|
||||
+ if (ret == ACT_P_CREATED)
|
||||
+ tcf_idr_insert(tn, *a);
|
||||
+
|
||||
+ return ret;
|
||||
+
|
||||
+put_chain:
|
||||
+/* if (goto_ch)
|
||||
+ tcf_chain_put_by_act(goto_ch);
|
||||
+release_idr: */
|
||||
+ tcf_idr_release(*a, bind);
|
||||
+ return err;
|
||||
+}
|
||||
+
|
||||
+static int tcf_ctinfo_dump(struct sk_buff *skb, struct tc_action *a,
|
||||
+ int bind, int ref)
|
||||
+{
|
||||
+ struct tcf_ctinfo *ci = to_ctinfo(a);
|
||||
+ struct tc_ctinfo opt = {
|
||||
+ .index = ci->tcf_index,
|
||||
+ .refcnt = refcount_read(&ci->tcf_refcnt) - ref,
|
||||
+ .bindcnt = atomic_read(&ci->tcf_bindcnt) - bind,
|
||||
+ };
|
||||
+ unsigned char *b = skb_tail_pointer(skb);
|
||||
+ struct tcf_ctinfo_params *cp;
|
||||
+ struct tcf_t t;
|
||||
+
|
||||
+ spin_lock_bh(&ci->tcf_lock);
|
||||
+ cp = rcu_dereference_protected(ci->params,
|
||||
+ lockdep_is_held(&ci->tcf_lock));
|
||||
+
|
||||
+ tcf_tm_dump(&t, &ci->tcf_tm);
|
||||
+ if (nla_put_64bit(skb, TCA_CTINFO_TM, sizeof(t), &t, TCA_CTINFO_PAD))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ opt.action = ci->tcf_action;
|
||||
+ if (nla_put(skb, TCA_CTINFO_ACT, sizeof(opt), &opt))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ if (nla_put_u16(skb, TCA_CTINFO_ZONE, cp->zone))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ if (cp->mode & CTINFO_MODE_DSCP) {
|
||||
+ if (nla_put_u32(skb, TCA_CTINFO_PARMS_DSCP_MASK,
|
||||
+ cp->dscpmask))
|
||||
+ goto nla_put_failure;
|
||||
+ if (nla_put_u32(skb, TCA_CTINFO_PARMS_DSCP_STATEMASK,
|
||||
+ cp->dscpstatemask))
|
||||
+ goto nla_put_failure;
|
||||
+ }
|
||||
+
|
||||
+ if (cp->mode & CTINFO_MODE_CPMARK) {
|
||||
+ if (nla_put_u32(skb, TCA_CTINFO_PARMS_CPMARK_MASK,
|
||||
+ cp->cpmarkmask))
|
||||
+ goto nla_put_failure;
|
||||
+ }
|
||||
+
|
||||
+ if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_DSCP_SET,
|
||||
+ ci->stats_dscp_set, TCA_CTINFO_PAD))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_DSCP_ERROR,
|
||||
+ ci->stats_dscp_error, TCA_CTINFO_PAD))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ if (nla_put_u64_64bit(skb, TCA_CTINFO_STATS_CPMARK_SET,
|
||||
+ ci->stats_cpmark_set, TCA_CTINFO_PAD))
|
||||
+ goto nla_put_failure;
|
||||
+
|
||||
+ spin_unlock_bh(&ci->tcf_lock);
|
||||
+ return skb->len;
|
||||
+
|
||||
+nla_put_failure:
|
||||
+ spin_unlock_bh(&ci->tcf_lock);
|
||||
+ nlmsg_trim(skb, b);
|
||||
+ return -1;
|
||||
+}
|
||||
+
|
||||
+static int tcf_ctinfo_walker(struct net *net, struct sk_buff *skb,
|
||||
+ struct netlink_callback *cb, int type,
|
||||
+ const struct tc_action_ops *ops,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
|
||||
+
|
||||
+ return tcf_generic_walker(tn, skb, cb, type, ops, extack);
|
||||
+}
|
||||
+
|
||||
+static int tcf_ctinfo_search(struct net *net, struct tc_action **a, u32 index,
|
||||
+ struct netlink_ext_ack *extack)
|
||||
+{
|
||||
+ struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
|
||||
+
|
||||
+ return tcf_idr_search(tn, a, index);
|
||||
+}
|
||||
+
|
||||
+static void tcf_ctinfo_cleanup(struct tc_action *a)
|
||||
+{
|
||||
+ struct tcf_ctinfo *ci = to_ctinfo(a);
|
||||
+ struct tcf_ctinfo_params *cp;
|
||||
+
|
||||
+ cp = rcu_dereference_protected(ci->params, 1);
|
||||
+ if (cp)
|
||||
+ kfree_rcu(cp, rcu);
|
||||
+}
|
||||
+
|
||||
+static struct tc_action_ops act_ctinfo_ops = {
|
||||
+ .kind = "ctinfo",
|
||||
+ .type = TCA_ID_CTINFO,
|
||||
+ .owner = THIS_MODULE,
|
||||
+ .act = tcf_ctinfo_act,
|
||||
+ .dump = tcf_ctinfo_dump,
|
||||
+ .init = tcf_ctinfo_init,
|
||||
+ .walk = tcf_ctinfo_walker,
|
||||
+ .cleanup= tcf_ctinfo_cleanup,
|
||||
+ .lookup = tcf_ctinfo_search,
|
||||
+ .size = sizeof(struct tcf_ctinfo),
|
||||
+};
|
||||
+
|
||||
+static __net_init int ctinfo_init_net(struct net *net)
|
||||
+{
|
||||
+ struct tc_action_net *tn = net_generic(net, ctinfo_net_id);
|
||||
+
|
||||
+ return tc_action_net_init(net, tn, &act_ctinfo_ops);
|
||||
+}
|
||||
+
|
||||
+static void __net_exit ctinfo_exit_net(struct list_head *net_list)
|
||||
+{
|
||||
+ tc_action_net_exit(net_list, ctinfo_net_id);
|
||||
+}
|
||||
+
|
||||
+static struct pernet_operations ctinfo_net_ops = {
|
||||
+ .init = ctinfo_init_net,
|
||||
+ .exit_batch = ctinfo_exit_net,
|
||||
+ .id = &ctinfo_net_id,
|
||||
+ .size = sizeof(struct tc_action_net),
|
||||
+};
|
||||
+
|
||||
+static int __init ctinfo_init_module(void)
|
||||
+{
|
||||
+ return tcf_register_action(&act_ctinfo_ops, &ctinfo_net_ops);
|
||||
+}
|
||||
+
|
||||
+static void __exit ctinfo_cleanup_module(void)
|
||||
+{
|
||||
+ tcf_unregister_action(&act_ctinfo_ops, &ctinfo_net_ops);
|
||||
+}
|
||||
+
|
||||
+module_init(ctinfo_init_module);
|
||||
+module_exit(ctinfo_cleanup_module);
|
||||
+MODULE_AUTHOR("Kevin Darbyshire-Bryant <ldir@darbyshire-bryant.me.uk>");
|
||||
+MODULE_DESCRIPTION("Connection tracking mark actions");
|
||||
+MODULE_LICENSE("GPL");
|
||||
--- a/tools/testing/selftests/tc-testing/config
|
||||
+++ b/tools/testing/selftests/tc-testing/config
|
||||
@@ -38,6 +38,7 @@ CONFIG_NET_ACT_CSUM=m
|
||||
CONFIG_NET_ACT_VLAN=m
|
||||
CONFIG_NET_ACT_BPF=m
|
||||
CONFIG_NET_ACT_CONNMARK=m
|
||||
+CONFIG_NET_ACT_CONNCTINFO=m
|
||||
CONFIG_NET_ACT_SKBMOD=m
|
||||
CONFIG_NET_ACT_IFE=m
|
||||
CONFIG_NET_ACT_TUNNEL_KEY=m
|
@ -0,0 +1,37 @@
|
||||
From 9a4d83074769d6ecf1f5c3fef0f183b09abf3726 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Marko <robimarko@gmail.com>
|
||||
Date: Sat, 6 Oct 2018 17:36:42 +0200
|
||||
Subject: [PATCH 1/8] mtd: spinand: winbond: Add support for W25N01GV
|
||||
|
||||
W25N01GV is a single die version of the already supported
|
||||
W25M02GV with half the capacity. Everything else is the
|
||||
same so introduce support for W25N01GV.
|
||||
|
||||
Datasheet:http://www.winbond.com/resource-files/w25n01gv%20revl%20050918%20unsecured.pdf
|
||||
|
||||
Tested on 8devices Jalapeno dev board under OpenWrt running 4.19-rc5.
|
||||
|
||||
Signed-off-by: Robert Marko <robimarko@gmail.com>
|
||||
Reviewed-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/winbond.c | 8 ++++++++
|
||||
1 file changed, 8 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/spi/winbond.c
|
||||
+++ b/drivers/mtd/nand/spi/winbond.c
|
||||
@@ -84,6 +84,14 @@ static const struct spinand_info winbond
|
||||
0,
|
||||
SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL),
|
||||
SPINAND_SELECT_TARGET(w25m02gv_select_target)),
|
||||
+ SPINAND_INFO("W25N01GV", 0xAA,
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(1, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&w25m02gv_ooblayout, NULL)),
|
||||
};
|
||||
|
||||
/**
|
@ -0,0 +1,188 @@
|
||||
From 10949af1681d5bb5cdbcc012815c6e40eec17d02 Mon Sep 17 00:00:00 2001
|
||||
From: Schrempf Frieder <frieder.schrempf@kontron.De>
|
||||
Date: Thu, 8 Nov 2018 08:32:11 +0000
|
||||
Subject: [PATCH 2/8] mtd: spinand: Add initial support for Toshiba TC58CVG2S0H
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add minimal support for the Toshiba TC58CVG2S0H SPI NAND chip.
|
||||
|
||||
Signed-off-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Acked-by: Clément Péron <peron.clem@gmail.com>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/Makefile | 2 +-
|
||||
drivers/mtd/nand/spi/core.c | 1 +
|
||||
drivers/mtd/nand/spi/toshiba.c | 137 +++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/spinand.h | 1 +
|
||||
4 files changed, 140 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/mtd/nand/spi/toshiba.c
|
||||
|
||||
--- a/drivers/mtd/nand/spi/Makefile
|
||||
+++ b/drivers/mtd/nand/spi/Makefile
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
-spinand-objs := core.o macronix.o micron.o winbond.o
|
||||
+spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -764,6 +764,7 @@ static const struct nand_ops spinand_ops
|
||||
static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
+ &toshiba_spinand_manufacturer,
|
||||
&winbond_spinand_manufacturer,
|
||||
};
|
||||
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/spi/toshiba.c
|
||||
@@ -0,0 +1,137 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Copyright (c) 2018 exceet electronics GmbH
|
||||
+ * Copyright (c) 2018 Kontron Electronics GmbH
|
||||
+ *
|
||||
+ * Author: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mtd/spinand.h>
|
||||
+
|
||||
+#define SPINAND_MFR_TOSHIBA 0x98
|
||||
+#define TOSH_STATUS_ECC_HAS_BITFLIPS_T (3 << 4)
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
+
|
||||
+static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 7)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = 128 + 16 * section;
|
||||
+ region->length = 16;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 0)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ /* 2 bytes reserved for BBM */
|
||||
+ region->offset = 2;
|
||||
+ region->length = 126;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
|
||||
+ .ecc = tc58cvg2s0h_ooblayout_ecc,
|
||||
+ .free = tc58cvg2s0h_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
+static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ struct nand_device *nand = spinand_to_nand(spinand);
|
||||
+ u8 mbf = 0;
|
||||
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(0x30, &mbf);
|
||||
+
|
||||
+ switch (status & STATUS_ECC_MASK) {
|
||||
+ case STATUS_ECC_NO_BITFLIPS:
|
||||
+ return 0;
|
||||
+
|
||||
+ case STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+
|
||||
+ case STATUS_ECC_HAS_BITFLIPS:
|
||||
+ case TOSH_STATUS_ECC_HAS_BITFLIPS_T:
|
||||
+ /*
|
||||
+ * Let's try to retrieve the real maximum number of bitflips
|
||||
+ * in order to avoid forcing the wear-leveling layer to move
|
||||
+ * data around if it's not necessary.
|
||||
+ */
|
||||
+ if (spi_mem_exec_op(spinand->spimem, &op))
|
||||
+ return nand->eccreq.strength;
|
||||
+
|
||||
+ mbf >>= 4;
|
||||
+
|
||||
+ if (WARN_ON(mbf > nand->eccreq.strength || !mbf))
|
||||
+ return nand->eccreq.strength;
|
||||
+
|
||||
+ return mbf;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static const struct spinand_info toshiba_spinand_table[] = {
|
||||
+ SPINAND_INFO("TC58CVG2S0H", 0xCD,
|
||||
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ SPINAND_HAS_QE_BIT,
|
||||
+ SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
|
||||
+ tc58cvg2s0h_ecc_get_status)),
|
||||
+};
|
||||
+
|
||||
+static int toshiba_spinand_detect(struct spinand_device *spinand)
|
||||
+{
|
||||
+ u8 *id = spinand->id.data;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * Toshiba SPI NAND read ID needs a dummy byte,
|
||||
+ * so the first byte in id is garbage.
|
||||
+ */
|
||||
+ if (id[1] != SPINAND_MFR_TOSHIBA)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = spinand_match_and_init(spinand, toshiba_spinand_table,
|
||||
+ ARRAY_SIZE(toshiba_spinand_table),
|
||||
+ id[2]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static const struct spinand_manufacturer_ops toshiba_spinand_manuf_ops = {
|
||||
+ .detect = toshiba_spinand_detect,
|
||||
+};
|
||||
+
|
||||
+const struct spinand_manufacturer toshiba_spinand_manufacturer = {
|
||||
+ .id = SPINAND_MFR_TOSHIBA,
|
||||
+ .name = "Toshiba",
|
||||
+ .ops = &toshiba_spinand_manuf_ops,
|
||||
+};
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -196,6 +196,7 @@ struct spinand_manufacturer {
|
||||
/* SPI NAND manufacturers */
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
+extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
|
||||
/**
|
@ -0,0 +1,196 @@
|
||||
From c93c613214ac70c87beab5422a60077bf126b855 Mon Sep 17 00:00:00 2001
|
||||
From: Chuanhong Guo <gch981213@gmail.com>
|
||||
Date: Wed, 28 Nov 2018 21:07:25 +0800
|
||||
Subject: [PATCH 3/8] mtd: spinand: add support for GigaDevice GD5FxGQ4xA
|
||||
|
||||
Add support for GigaDevice GD5F1G/2G/4GQ4xA SPI NAND.
|
||||
|
||||
Signed-off-by: Chuanhong Guo <gch981213@gmail.com>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/Makefile | 2 +-
|
||||
drivers/mtd/nand/spi/core.c | 1 +
|
||||
drivers/mtd/nand/spi/gigadevice.c | 148 ++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/spinand.h | 1 +
|
||||
4 files changed, 151 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/mtd/nand/spi/gigadevice.c
|
||||
|
||||
--- a/drivers/mtd/nand/spi/Makefile
|
||||
+++ b/drivers/mtd/nand/spi/Makefile
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
-spinand-objs := core.o macronix.o micron.o toshiba.o winbond.o
|
||||
+spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -762,6 +762,7 @@ static const struct nand_ops spinand_ops
|
||||
};
|
||||
|
||||
static const struct spinand_manufacturer *spinand_manufacturers[] = {
|
||||
+ &gigadevice_spinand_manufacturer,
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
&toshiba_spinand_manufacturer,
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/spi/gigadevice.c
|
||||
@@ -0,0 +1,148 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Author:
|
||||
+ * Chuanhong Guo <gch981213@gmail.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mtd/spinand.h>
|
||||
+
|
||||
+#define SPINAND_MFR_GIGADEVICE 0xC8
|
||||
+#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
|
||||
+#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
+
|
||||
+static int gd5fxgq4xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 3)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = (16 * section) + 8;
|
||||
+ region->length = 8;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gd5fxgq4xa_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 3)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ if (section) {
|
||||
+ region->offset = 16 * section;
|
||||
+ region->length = 8;
|
||||
+ } else {
|
||||
+ /* section 0 has one byte reserved for bad block mark */
|
||||
+ region->offset = 1;
|
||||
+ region->length = 7;
|
||||
+ }
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ switch (status & STATUS_ECC_MASK) {
|
||||
+ case STATUS_ECC_NO_BITFLIPS:
|
||||
+ return 0;
|
||||
+
|
||||
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
|
||||
+ /* 1-7 bits are flipped. return the maximum. */
|
||||
+ return 7;
|
||||
+
|
||||
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
|
||||
+ return 8;
|
||||
+
|
||||
+ case STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
|
||||
+ .ecc = gd5fxgq4xa_ooblayout_ecc,
|
||||
+ .free = gd5fxgq4xa_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
+static const struct spinand_info gigadevice_spinand_table[] = {
|
||||
+ SPINAND_INFO("GD5F1GQ4xA", 0xF1,
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
|
||||
+ gd5fxgq4xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("GD5F2GQ4xA", 0xF2,
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
|
||||
+ gd5fxgq4xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("GD5F4GQ4xA", 0xF4,
|
||||
+ NAND_MEMORG(1, 2048, 64, 64, 4096, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
|
||||
+ gd5fxgq4xa_ecc_get_status)),
|
||||
+};
|
||||
+
|
||||
+static int gigadevice_spinand_detect(struct spinand_device *spinand)
|
||||
+{
|
||||
+ u8 *id = spinand->id.data;
|
||||
+ int ret;
|
||||
+
|
||||
+ /*
|
||||
+ * For GD NANDs, There is an address byte needed to shift in before IDs
|
||||
+ * are read out, so the first byte in raw_id is dummy.
|
||||
+ */
|
||||
+ if (id[1] != SPINAND_MFR_GIGADEVICE)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
|
||||
+ ARRAY_SIZE(gigadevice_spinand_table),
|
||||
+ id[2]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static const struct spinand_manufacturer_ops gigadevice_spinand_manuf_ops = {
|
||||
+ .detect = gigadevice_spinand_detect,
|
||||
+};
|
||||
+
|
||||
+const struct spinand_manufacturer gigadevice_spinand_manufacturer = {
|
||||
+ .id = SPINAND_MFR_GIGADEVICE,
|
||||
+ .name = "GigaDevice",
|
||||
+ .ops = &gigadevice_spinand_manuf_ops,
|
||||
+};
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -194,6 +194,7 @@ struct spinand_manufacturer {
|
||||
};
|
||||
|
||||
/* SPI NAND manufacturers */
|
||||
+extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
@ -0,0 +1,136 @@
|
||||
From db214513f62fd13c0a9af3bd5c5d634dba37e65d Mon Sep 17 00:00:00 2001
|
||||
From: Yoshio Furuyama <tmcmc-mb-yfuruyama7@ml.toshiba.co.jp>
|
||||
Date: Wed, 16 Jan 2019 14:53:19 +0900
|
||||
Subject: [PATCH 7/8] mtd: spinand: Add support for all Toshiba Memory products
|
||||
|
||||
Add device table for Toshiba Memory products.
|
||||
Also, generalize OOB layout structure and function names.
|
||||
|
||||
Signed-off-by: Yoshio Furuyama <tmcmc-mb-yfuruyama7@ml.toshiba.co.jp>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/toshiba.c | 79 ++++++++++++++++++++++++++++------
|
||||
1 file changed, 65 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/spi/toshiba.c
|
||||
+++ b/drivers/mtd/nand/spi/toshiba.c
|
||||
@@ -25,19 +25,19 @@ static SPINAND_OP_VARIANTS(write_cache_v
|
||||
static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
|
||||
-static int tc58cvg2s0h_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+static int tc58cxgxsx_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
- if (section > 7)
|
||||
+ if (section > 0)
|
||||
return -ERANGE;
|
||||
|
||||
- region->offset = 128 + 16 * section;
|
||||
- region->length = 16;
|
||||
+ region->offset = mtd->oobsize / 2;
|
||||
+ region->length = mtd->oobsize / 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int tc58cvg2s0h_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+static int tc58cxgxsx_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section > 0)
|
||||
@@ -45,17 +45,17 @@ static int tc58cvg2s0h_ooblayout_free(st
|
||||
|
||||
/* 2 bytes reserved for BBM */
|
||||
region->offset = 2;
|
||||
- region->length = 126;
|
||||
+ region->length = (mtd->oobsize / 2) - 2;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static const struct mtd_ooblayout_ops tc58cvg2s0h_ooblayout = {
|
||||
- .ecc = tc58cvg2s0h_ooblayout_ecc,
|
||||
- .free = tc58cvg2s0h_ooblayout_free,
|
||||
+static const struct mtd_ooblayout_ops tc58cxgxsx_ooblayout = {
|
||||
+ .ecc = tc58cxgxsx_ooblayout_ecc,
|
||||
+ .free = tc58cxgxsx_ooblayout_free,
|
||||
};
|
||||
|
||||
-static int tc58cvg2s0h_ecc_get_status(struct spinand_device *spinand,
|
||||
+static int tc58cxgxsx_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
@@ -94,15 +94,66 @@ static int tc58cvg2s0h_ecc_get_status(st
|
||||
}
|
||||
|
||||
static const struct spinand_info toshiba_spinand_table[] = {
|
||||
- SPINAND_INFO("TC58CVG2S0H", 0xCD,
|
||||
+ /* 3.3V 1Gb */
|
||||
+ SPINAND_INFO("TC58CVG0S3", 0xC2,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
+ /* 3.3V 2Gb */
|
||||
+ SPINAND_INFO("TC58CVG1S3", 0xCB,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
+ /* 3.3V 4Gb */
|
||||
+ SPINAND_INFO("TC58CVG2S0", 0xCD,
|
||||
+ NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
+ /* 1.8V 1Gb */
|
||||
+ SPINAND_INFO("TC58CYG0S3", 0xB2,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
+ /* 1.8V 2Gb */
|
||||
+ SPINAND_INFO("TC58CYG1S3", 0xBB,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
+ /* 1.8V 4Gb */
|
||||
+ SPINAND_INFO("TC58CYG2S0", 0xBD,
|
||||
NAND_MEMORG(1, 4096, 256, 64, 2048, 1, 1, 1),
|
||||
NAND_ECCREQ(8, 512),
|
||||
SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
- SPINAND_HAS_QE_BIT,
|
||||
- SPINAND_ECCINFO(&tc58cvg2s0h_ooblayout,
|
||||
- tc58cvg2s0h_ecc_get_status)),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&tc58cxgxsx_ooblayout,
|
||||
+ tc58cxgxsx_ecc_get_status)),
|
||||
};
|
||||
|
||||
static int toshiba_spinand_detect(struct spinand_device *spinand)
|
@ -0,0 +1,129 @@
|
||||
From c40c7a990a46e5102a1cc4190557bf315d32d80d Mon Sep 17 00:00:00 2001
|
||||
From: Stefan Roese <sr@denx.de>
|
||||
Date: Thu, 24 Jan 2019 13:48:06 +0100
|
||||
Subject: [PATCH 8/8] mtd: spinand: Add support for GigaDevice GD5F1GQ4UExxG
|
||||
|
||||
Add support for GigaDevice GD5F1GQ4UExxG SPI NAND chip.
|
||||
|
||||
Signed-off-by: Stefan Roese <sr@denx.de>
|
||||
Cc: Chuanhong Guo <gch981213@gmail.com>
|
||||
Cc: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Cc: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
Cc: Boris Brezillon <bbrezillon@kernel.org>
|
||||
Reviewed-by: Boris Brezillon <bbrezillon@kernel.org>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/gigadevice.c | 83 +++++++++++++++++++++++++++++++
|
||||
1 file changed, 83 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/nand/spi/gigadevice.c
|
||||
+++ b/drivers/mtd/nand/spi/gigadevice.c
|
||||
@@ -12,6 +12,8 @@
|
||||
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
|
||||
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
|
||||
|
||||
+#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
|
||||
+
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
@@ -81,11 +83,83 @@ static int gd5fxgq4xa_ecc_get_status(str
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = 64;
|
||||
+ region->length = 64;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ /* Reserve 1 bytes for the BBM. */
|
||||
+ region->offset = 1;
|
||||
+ region->length = 63;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ u8 status2;
|
||||
+ struct spi_mem_op op = SPINAND_GET_FEATURE_OP(GD5FXGQ4UEXXG_REG_STATUS2,
|
||||
+ &status2);
|
||||
+ int ret;
|
||||
+
|
||||
+ switch (status & STATUS_ECC_MASK) {
|
||||
+ case STATUS_ECC_NO_BITFLIPS:
|
||||
+ return 0;
|
||||
+
|
||||
+ case GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS:
|
||||
+ /*
|
||||
+ * Read status2 register to determine a more fine grained
|
||||
+ * bit error status
|
||||
+ */
|
||||
+ ret = spi_mem_exec_op(spinand->spimem, &op);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ /*
|
||||
+ * 4 ... 7 bits are flipped (1..4 can't be detected, so
|
||||
+ * report the maximum of 4 in this case
|
||||
+ */
|
||||
+ /* bits sorted this way (3...0): ECCS1,ECCS0,ECCSE1,ECCSE0 */
|
||||
+ return ((status & STATUS_ECC_MASK) >> 2) |
|
||||
+ ((status2 & STATUS_ECC_MASK) >> 4);
|
||||
+
|
||||
+ case GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS:
|
||||
+ return 8;
|
||||
+
|
||||
+ case STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
|
||||
.ecc = gd5fxgq4xa_ooblayout_ecc,
|
||||
.free = gd5fxgq4xa_ooblayout_free,
|
||||
};
|
||||
|
||||
+static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
|
||||
+ .ecc = gd5fxgq4uexxg_ooblayout_ecc,
|
||||
+ .free = gd5fxgq4uexxg_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
static const struct spinand_info gigadevice_spinand_table[] = {
|
||||
SPINAND_INFO("GD5F1GQ4xA", 0xF1,
|
||||
NAND_MEMORG(1, 2048, 64, 64, 1024, 1, 1, 1),
|
||||
@@ -114,6 +188,15 @@ static const struct spinand_info gigadev
|
||||
0,
|
||||
SPINAND_ECCINFO(&gd5fxgq4xa_ooblayout,
|
||||
gd5fxgq4xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("GD5F1GQ4UExxG", 0xd1,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
|
||||
+ gd5fxgq4uexxg_ecc_get_status)),
|
||||
};
|
||||
|
||||
static int gigadevice_spinand_detect(struct spinand_device *spinand)
|
@ -0,0 +1,25 @@
|
||||
From 81554171373018b83f3554b9e725d2b5bf1844a5 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Sverdlin <alexander.sverdlin@nokia.com>
|
||||
Date: Fri, 13 Jul 2018 15:06:46 +0200
|
||||
Subject: [PATCH] mtd: spi-nor: Add support for mx25u12835f
|
||||
|
||||
This chip supports dual and quad read and uniform 4K-byte erase.
|
||||
|
||||
Signed-off-by: Alexander Sverdlin <alexander.sverdlin@nokia.com>
|
||||
Reviewed-by: Tudor Ambarus <tudor.ambarus@microchip.com>
|
||||
Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
|
||||
---
|
||||
drivers/mtd/spi-nor/spi-nor.c | 2 ++
|
||||
1 file changed, 2 insertions(+)
|
||||
|
||||
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||
@@ -1088,6 +1088,8 @@ static const struct flash_info spi_nor_i
|
||||
{ "mx25u6435f", INFO(0xc22537, 0, 64 * 1024, 128, SECT_4K) },
|
||||
{ "mx25l12805d", INFO(0xc22018, 0, 64 * 1024, 256, 0) },
|
||||
{ "mx25l12855e", INFO(0xc22618, 0, 64 * 1024, 256, 0) },
|
||||
+ { "mx25u12835f", INFO(0xc22538, 0, 64 * 1024, 256,
|
||||
+ SECT_4K | SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "mx25l25635e", INFO(0xc22019, 0, 64 * 1024, 512, SPI_NOR_DUAL_READ | SPI_NOR_QUAD_READ) },
|
||||
{ "mx25u25635f", INFO(0xc22539, 0, 64 * 1024, 512, SECT_4K | SPI_NOR_4B_OPCODES) },
|
||||
{ "mx25l25655e", INFO(0xc22619, 0, 64 * 1024, 512, 0) },
|
@ -0,0 +1,81 @@
|
||||
From d014717d50b1efd011a3a028ce92563a4dc9bae5 Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Date: Wed, 22 May 2019 15:05:53 -0700
|
||||
Subject: [PATCH 1/3] mtd: spinand: Define macros for page-read ops with
|
||||
three-byte addresses
|
||||
|
||||
The GigaDevice GD5F1GQ4UFxxG SPI NAND utilizes three-byte addresses
|
||||
for its page-read ops.
|
||||
|
||||
http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
|
||||
|
||||
Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
include/linux/mtd/spinand.h | 30 ++++++++++++++++++++++++++++++
|
||||
1 file changed, 30 insertions(+)
|
||||
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -68,30 +68,60 @@
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
|
||||
+#define SPINAND_PAGE_READ_FROM_CACHE_OP_3A(fast, addr, ndummy, buf, len) \
|
||||
+ SPI_MEM_OP(SPI_MEM_OP_CMD(fast ? 0x0b : 0x03, 1), \
|
||||
+ SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
+ SPI_MEM_OP_DATA_IN(len, buf, 1))
|
||||
+
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
+#define SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(addr, ndummy, buf, len) \
|
||||
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0x3b, 1), \
|
||||
+ SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
+ SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
+
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 1), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
+#define SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(addr, ndummy, buf, len) \
|
||||
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0x6b, 1), \
|
||||
+ SPI_MEM_OP_ADDR(3, addr, 1), \
|
||||
+ SPI_MEM_OP_DUMMY(ndummy, 1), \
|
||||
+ SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
+
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 2), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
|
||||
+#define SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP_3A(addr, ndummy, buf, len) \
|
||||
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0xbb, 1), \
|
||||
+ SPI_MEM_OP_ADDR(3, addr, 2), \
|
||||
+ SPI_MEM_OP_DUMMY(ndummy, 2), \
|
||||
+ SPI_MEM_OP_DATA_IN(len, buf, 2))
|
||||
+
|
||||
#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(addr, ndummy, buf, len) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
SPI_MEM_OP_ADDR(2, addr, 4), \
|
||||
SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
|
||||
+#define SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP_3A(addr, ndummy, buf, len) \
|
||||
+ SPI_MEM_OP(SPI_MEM_OP_CMD(0xeb, 1), \
|
||||
+ SPI_MEM_OP_ADDR(3, addr, 4), \
|
||||
+ SPI_MEM_OP_DUMMY(ndummy, 4), \
|
||||
+ SPI_MEM_OP_DATA_IN(len, buf, 4))
|
||||
+
|
||||
#define SPINAND_PROG_EXEC_OP(addr) \
|
||||
SPI_MEM_OP(SPI_MEM_OP_CMD(0x10, 1), \
|
||||
SPI_MEM_OP_ADDR(3, addr, 1), \
|
@ -0,0 +1,48 @@
|
||||
From 53dd94a79d3bfdaae30e5a4ebf474ea1af1d572e Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Date: Wed, 22 May 2019 15:05:54 -0700
|
||||
Subject: [PATCH 2/3] mtd: spinand: Add support for two-byte device IDs
|
||||
|
||||
The GigaDevice GD5F1GQ4UFxxG SPI NAND utilizes two-byte device IDs.
|
||||
|
||||
http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
|
||||
|
||||
Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/core.c | 2 +-
|
||||
include/linux/mtd/spinand.h | 4 ++--
|
||||
2 files changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -853,7 +853,7 @@ spinand_select_op_variant(struct spinand
|
||||
*/
|
||||
int spinand_match_and_init(struct spinand_device *spinand,
|
||||
const struct spinand_info *table,
|
||||
- unsigned int table_size, u8 devid)
|
||||
+ unsigned int table_size, u16 devid)
|
||||
{
|
||||
struct nand_device *nand = spinand_to_nand(spinand);
|
||||
unsigned int i;
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -290,7 +290,7 @@ struct spinand_ecc_info {
|
||||
*/
|
||||
struct spinand_info {
|
||||
const char *model;
|
||||
- u8 devid;
|
||||
+ u16 devid;
|
||||
u32 flags;
|
||||
struct nand_memory_organization memorg;
|
||||
struct nand_ecc_req eccreq;
|
||||
@@ -445,7 +445,7 @@ static inline void spinand_set_of_node(s
|
||||
|
||||
int spinand_match_and_init(struct spinand_device *dev,
|
||||
const struct spinand_info *table,
|
||||
- unsigned int table_size, u8 devid);
|
||||
+ unsigned int table_size, u16 devid);
|
||||
|
||||
int spinand_upd_cfg(struct spinand_device *spinand, u8 mask, u8 val);
|
||||
int spinand_select_target(struct spinand_device *spinand, unsigned int target);
|
@ -0,0 +1,197 @@
|
||||
|
||||
IMPORTANT NOTE
|
||||
==============
|
||||
|
||||
The content of this patch has been adapted for Linux 4.19
|
||||
|
||||
Changes were made in Linux 5.x to add the bad-block limit
|
||||
to the metadata available to the driver, adding a parameter
|
||||
|
||||
NAND_MEMORG(1, 2048, 128, 64, 1024, 20, 1, 1, 1),
|
||||
^- New bad-block limit
|
||||
|
||||
This patch omits that parameter from the upstream patch
|
||||
for compatibility with the Linux 4.19 driver.
|
||||
|
||||
=====
|
||||
|
||||
From 049df13c4e63884fe6634db5568e08f65922256e Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Date: Wed, 22 May 2019 15:05:55 -0700
|
||||
Subject: [PATCH 3/3] mtd: spinand: Add support for GigaDevice GD5F1GQ4UFxxG
|
||||
|
||||
The GigaDevice GD5F1GQ4UFxxG SPI NAND is in current production devices
|
||||
and, while it has the same logical layout as the E-series devices,
|
||||
it differs in the SPI interfacing in significant ways.
|
||||
|
||||
This support is contingent on previous commits to:
|
||||
|
||||
* Add support for two-byte device IDs
|
||||
* Define macros for page-read ops with three-byte addresses
|
||||
|
||||
http://www.gigadevice.com/datasheet/gd5f1gq4xfxxg/
|
||||
|
||||
Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
---
|
||||
drivers/mtd/nand/spi/gigadevice.c | 79 +++++++++++++++++++++++++------
|
||||
1 file changed, 64 insertions(+), 15 deletions(-)
|
||||
|
||||
--- a/drivers/mtd/nand/spi/gigadevice.c
|
||||
+++ b/drivers/mtd/nand/spi/gigadevice.c
|
||||
@@ -9,11 +9,17 @@
|
||||
#include <linux/mtd/spinand.h>
|
||||
|
||||
#define SPINAND_MFR_GIGADEVICE 0xC8
|
||||
+
|
||||
#define GD5FXGQ4XA_STATUS_ECC_1_7_BITFLIPS (1 << 4)
|
||||
#define GD5FXGQ4XA_STATUS_ECC_8_BITFLIPS (3 << 4)
|
||||
|
||||
#define GD5FXGQ4UEXXG_REG_STATUS2 0xf0
|
||||
|
||||
+#define GD5FXGQ4UXFXXG_STATUS_ECC_MASK (7 << 4)
|
||||
+#define GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS (0 << 4)
|
||||
+#define GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS (1 << 4)
|
||||
+#define GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR (7 << 4)
|
||||
+
|
||||
static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
@@ -22,6 +28,14 @@ static SPINAND_OP_VARIANTS(read_cache_va
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants_f,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP_3A(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP_3A(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP_3A(false, 0, 0, NULL, 0));
|
||||
+
|
||||
static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
@@ -59,6 +73,11 @@ static int gd5fxgq4xa_ooblayout_free(str
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
|
||||
+ .ecc = gd5fxgq4xa_ooblayout_ecc,
|
||||
+ .free = gd5fxgq4xa_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
static int gd5fxgq4xa_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
@@ -83,7 +102,7 @@ static int gd5fxgq4xa_ecc_get_status(str
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
-static int gd5fxgq4uexxg_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+static int gd5fxgq4_variant2_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section)
|
||||
@@ -95,7 +114,7 @@ static int gd5fxgq4uexxg_ooblayout_ecc(s
|
||||
return 0;
|
||||
}
|
||||
|
||||
-static int gd5fxgq4uexxg_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+static int gd5fxgq4_variant2_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
struct mtd_oob_region *region)
|
||||
{
|
||||
if (section)
|
||||
@@ -108,6 +127,11 @@ static int gd5fxgq4uexxg_ooblayout_free(
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static const struct mtd_ooblayout_ops gd5fxgq4_variant2_ooblayout = {
|
||||
+ .ecc = gd5fxgq4_variant2_ooblayout_ecc,
|
||||
+ .free = gd5fxgq4_variant2_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
static int gd5fxgq4uexxg_ecc_get_status(struct spinand_device *spinand,
|
||||
u8 status)
|
||||
{
|
||||
@@ -150,15 +174,25 @@ static int gd5fxgq4uexxg_ecc_get_status(
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
-static const struct mtd_ooblayout_ops gd5fxgq4xa_ooblayout = {
|
||||
- .ecc = gd5fxgq4xa_ooblayout_ecc,
|
||||
- .free = gd5fxgq4xa_ooblayout_free,
|
||||
-};
|
||||
+static int gd5fxgq4ufxxg_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ switch (status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) {
|
||||
+ case GD5FXGQ4UXFXXG_STATUS_ECC_NO_BITFLIPS:
|
||||
+ return 0;
|
||||
|
||||
-static const struct mtd_ooblayout_ops gd5fxgq4uexxg_ooblayout = {
|
||||
- .ecc = gd5fxgq4uexxg_ooblayout_ecc,
|
||||
- .free = gd5fxgq4uexxg_ooblayout_free,
|
||||
-};
|
||||
+ case GD5FXGQ4UXFXXG_STATUS_ECC_1_3_BITFLIPS:
|
||||
+ return 3;
|
||||
+
|
||||
+ case GD5FXGQ4UXFXXG_STATUS_ECC_UNCOR_ERROR:
|
||||
+ return -EBADMSG;
|
||||
+
|
||||
+ default: /* (2 << 4) through (6 << 4) are 4-8 corrected errors */
|
||||
+ return ((status & GD5FXGQ4UXFXXG_STATUS_ECC_MASK) >> 4) + 2;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
|
||||
static const struct spinand_info gigadevice_spinand_table[] = {
|
||||
SPINAND_INFO("GD5F1GQ4xA", 0xF1,
|
||||
@@ -195,25 +229,40 @@ static const struct spinand_info gigadev
|
||||
&write_cache_variants,
|
||||
&update_cache_variants),
|
||||
0,
|
||||
- SPINAND_ECCINFO(&gd5fxgq4uexxg_ooblayout,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
|
||||
gd5fxgq4uexxg_ecc_get_status)),
|
||||
+ SPINAND_INFO("GD5F1GQ4UFxxG", 0xb148,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants_f,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&gd5fxgq4_variant2_ooblayout,
|
||||
+ gd5fxgq4ufxxg_ecc_get_status)),
|
||||
};
|
||||
|
||||
static int gigadevice_spinand_detect(struct spinand_device *spinand)
|
||||
{
|
||||
u8 *id = spinand->id.data;
|
||||
+ u16 did;
|
||||
int ret;
|
||||
|
||||
/*
|
||||
- * For GD NANDs, There is an address byte needed to shift in before IDs
|
||||
- * are read out, so the first byte in raw_id is dummy.
|
||||
+ * Earlier GDF5-series devices (A,E) return [0][MID][DID]
|
||||
+ * Later (F) devices return [MID][DID1][DID2]
|
||||
*/
|
||||
- if (id[1] != SPINAND_MFR_GIGADEVICE)
|
||||
+
|
||||
+ if (id[0] == SPINAND_MFR_GIGADEVICE)
|
||||
+ did = (id[1] << 8) + id[2];
|
||||
+ else if (id[0] == 0 && id[1] == SPINAND_MFR_GIGADEVICE)
|
||||
+ did = id[2];
|
||||
+ else
|
||||
return 0;
|
||||
|
||||
ret = spinand_match_and_init(spinand, gigadevice_spinand_table,
|
||||
ARRAY_SIZE(gigadevice_spinand_table),
|
||||
- id[2]);
|
||||
+ did);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
@ -0,0 +1,203 @@
|
||||
From 3552691616c940a7c4125c2678ba816653cd725e Mon Sep 17 00:00:00 2001
|
||||
From: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Date: Tue, 18 Jun 2019 10:08:05 -0700
|
||||
Subject: [PATCH] mtd: spinand: Add initial support for Paragon PN26G0xA
|
||||
|
||||
Add initial support for Paragon Technology
|
||||
PN26G01Axxxxx and PN26G02Axxxxx SPI NAND
|
||||
|
||||
Datasheets available at
|
||||
http://www.xtxtech.com/upfile/2016082517274590.pdf
|
||||
http://www.xtxtech.com/upfile/2016082517282329.pdf
|
||||
|
||||
Signed-off-by: Jeff Kletsky <git-commits@allycomm.com>
|
||||
Reviewed-by: Frieder Schrempf <frieder.schrempf@kontron.de>
|
||||
Signed-off-by: Miquel Raynal <miquel.raynal@bootlin.com>
|
||||
|
||||
ADOPTED FROM UPSTREAM due to upstream commit 377e517b5fa5 in Linux 5.2
|
||||
which added another parameter to NAND_MEMORG
|
||||
---
|
||||
drivers/mtd/nand/spi/Makefile | 2 +-
|
||||
drivers/mtd/nand/spi/core.c | 1 +
|
||||
drivers/mtd/nand/spi/paragon.c | 147 +++++++++++++++++++++++++++++++++
|
||||
include/linux/mtd/spinand.h | 1 +
|
||||
4 files changed, 150 insertions(+), 1 deletion(-)
|
||||
create mode 100644 drivers/mtd/nand/spi/paragon.c
|
||||
|
||||
--- a/drivers/mtd/nand/spi/Makefile
|
||||
+++ b/drivers/mtd/nand/spi/Makefile
|
||||
@@ -1,3 +1,3 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
-spinand-objs := core.o gigadevice.o macronix.o micron.o toshiba.o winbond.o
|
||||
+spinand-objs := core.o gigadevice.o macronix.o micron.o paragon.o toshiba.o winbond.o
|
||||
obj-$(CONFIG_MTD_SPI_NAND) += spinand.o
|
||||
--- a/drivers/mtd/nand/spi/core.c
|
||||
+++ b/drivers/mtd/nand/spi/core.c
|
||||
@@ -765,6 +765,7 @@ static const struct spinand_manufacturer
|
||||
&gigadevice_spinand_manufacturer,
|
||||
¯onix_spinand_manufacturer,
|
||||
µn_spinand_manufacturer,
|
||||
+ ¶gon_spinand_manufacturer,
|
||||
&toshiba_spinand_manufacturer,
|
||||
&winbond_spinand_manufacturer,
|
||||
};
|
||||
--- /dev/null
|
||||
+++ b/drivers/mtd/nand/spi/paragon.c
|
||||
@@ -0,0 +1,147 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0
|
||||
+/*
|
||||
+ * Copyright (C) 2019 Jeff Kletsky
|
||||
+ *
|
||||
+ * Author: Jeff Kletsky <git-commits@allycomm.com>
|
||||
+ */
|
||||
+
|
||||
+#include <linux/device.h>
|
||||
+#include <linux/kernel.h>
|
||||
+#include <linux/mtd/spinand.h>
|
||||
+
|
||||
+
|
||||
+#define SPINAND_MFR_PARAGON 0xa1
|
||||
+
|
||||
+
|
||||
+#define PN26G0XA_STATUS_ECC_BITMASK (3 << 4)
|
||||
+
|
||||
+#define PN26G0XA_STATUS_ECC_NONE_DETECTED (0 << 4)
|
||||
+#define PN26G0XA_STATUS_ECC_1_7_CORRECTED (1 << 4)
|
||||
+#define PN26G0XA_STATUS_ECC_ERRORED (2 << 4)
|
||||
+#define PN26G0XA_STATUS_ECC_8_CORRECTED (3 << 4)
|
||||
+
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(read_cache_variants,
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_QUADIO_OP(0, 2, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X4_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_DUALIO_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_X2_OP(0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(true, 0, 1, NULL, 0),
|
||||
+ SPINAND_PAGE_READ_FROM_CACHE_OP(false, 0, 1, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(write_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(true, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(true, 0, NULL, 0));
|
||||
+
|
||||
+static SPINAND_OP_VARIANTS(update_cache_variants,
|
||||
+ SPINAND_PROG_LOAD_X4(false, 0, NULL, 0),
|
||||
+ SPINAND_PROG_LOAD(false, 0, NULL, 0));
|
||||
+
|
||||
+
|
||||
+static int pn26g0xa_ooblayout_ecc(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 3)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ region->offset = 6 + (15 * section); /* 4 BBM + 2 user bytes */
|
||||
+ region->length = 13;
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pn26g0xa_ooblayout_free(struct mtd_info *mtd, int section,
|
||||
+ struct mtd_oob_region *region)
|
||||
+{
|
||||
+ if (section > 4)
|
||||
+ return -ERANGE;
|
||||
+
|
||||
+ if (section == 4) {
|
||||
+ region->offset = 64;
|
||||
+ region->length = 64;
|
||||
+ } else {
|
||||
+ region->offset = 4 + (15 * section);
|
||||
+ region->length = 2;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int pn26g0xa_ecc_get_status(struct spinand_device *spinand,
|
||||
+ u8 status)
|
||||
+{
|
||||
+ switch (status & PN26G0XA_STATUS_ECC_BITMASK) {
|
||||
+ case PN26G0XA_STATUS_ECC_NONE_DETECTED:
|
||||
+ return 0;
|
||||
+
|
||||
+ case PN26G0XA_STATUS_ECC_1_7_CORRECTED:
|
||||
+ return 7; /* Return upper limit by convention */
|
||||
+
|
||||
+ case PN26G0XA_STATUS_ECC_8_CORRECTED:
|
||||
+ return 8;
|
||||
+
|
||||
+ case PN26G0XA_STATUS_ECC_ERRORED:
|
||||
+ return -EBADMSG;
|
||||
+
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+
|
||||
+ return -EINVAL;
|
||||
+}
|
||||
+
|
||||
+static const struct mtd_ooblayout_ops pn26g0xa_ooblayout = {
|
||||
+ .ecc = pn26g0xa_ooblayout_ecc,
|
||||
+ .free = pn26g0xa_ooblayout_free,
|
||||
+};
|
||||
+
|
||||
+
|
||||
+static const struct spinand_info paragon_spinand_table[] = {
|
||||
+ SPINAND_INFO("PN26G01A", 0xe1,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 1024, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
|
||||
+ pn26g0xa_ecc_get_status)),
|
||||
+ SPINAND_INFO("PN26G02A", 0xe2,
|
||||
+ NAND_MEMORG(1, 2048, 128, 64, 2048, 1, 1, 1),
|
||||
+ NAND_ECCREQ(8, 512),
|
||||
+ SPINAND_INFO_OP_VARIANTS(&read_cache_variants,
|
||||
+ &write_cache_variants,
|
||||
+ &update_cache_variants),
|
||||
+ 0,
|
||||
+ SPINAND_ECCINFO(&pn26g0xa_ooblayout,
|
||||
+ pn26g0xa_ecc_get_status)),
|
||||
+};
|
||||
+
|
||||
+static int paragon_spinand_detect(struct spinand_device *spinand)
|
||||
+{
|
||||
+ u8 *id = spinand->id.data;
|
||||
+ int ret;
|
||||
+
|
||||
+ /* Read ID returns [0][MID][DID] */
|
||||
+
|
||||
+ if (id[1] != SPINAND_MFR_PARAGON)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = spinand_match_and_init(spinand, paragon_spinand_table,
|
||||
+ ARRAY_SIZE(paragon_spinand_table),
|
||||
+ id[2]);
|
||||
+ if (ret)
|
||||
+ return ret;
|
||||
+
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
+static const struct spinand_manufacturer_ops paragon_spinand_manuf_ops = {
|
||||
+ .detect = paragon_spinand_detect,
|
||||
+};
|
||||
+
|
||||
+const struct spinand_manufacturer paragon_spinand_manufacturer = {
|
||||
+ .id = SPINAND_MFR_PARAGON,
|
||||
+ .name = "Paragon",
|
||||
+ .ops = ¶gon_spinand_manuf_ops,
|
||||
+};
|
||||
--- a/include/linux/mtd/spinand.h
|
||||
+++ b/include/linux/mtd/spinand.h
|
||||
@@ -227,6 +227,7 @@ struct spinand_manufacturer {
|
||||
extern const struct spinand_manufacturer gigadevice_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer macronix_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer micron_spinand_manufacturer;
|
||||
+extern const struct spinand_manufacturer paragon_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer toshiba_spinand_manufacturer;
|
||||
extern const struct spinand_manufacturer winbond_spinand_manufacturer;
|
||||
|
@ -0,0 +1,44 @@
|
||||
From 6f3ea4e5b1f0867ec217f6101fcb89783ed905d7 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sat, 9 Feb 2019 18:23:26 +0000
|
||||
Subject: [PATCH] net: phylink: only call mac_config() during resolve
|
||||
when link is up
|
||||
|
||||
There's little point calling mac_config() when the link is down.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 11 +++++++++--
|
||||
1 file changed, 9 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -339,6 +339,13 @@ static void phylink_mac_config(struct ph
|
||||
pl->ops->mac_config(pl->netdev, pl->link_an_mode, state);
|
||||
}
|
||||
|
||||
+static void phylink_mac_config_up(struct phylink *pl,
|
||||
+ const struct phylink_link_state *state)
|
||||
+{
|
||||
+ if (state->link)
|
||||
+ phylink_mac_config(pl, state);
|
||||
+}
|
||||
+
|
||||
static void phylink_mac_an_restart(struct phylink *pl)
|
||||
{
|
||||
if (pl->link_config.an_enabled &&
|
||||
@@ -442,12 +449,12 @@ static void phylink_resolve(struct work_
|
||||
case MLO_AN_PHY:
|
||||
link_state = pl->phy_state;
|
||||
phylink_resolve_flow(pl, &link_state);
|
||||
- phylink_mac_config(pl, &link_state);
|
||||
+ phylink_mac_config_up(pl, &link_state);
|
||||
break;
|
||||
|
||||
case MLO_AN_FIXED:
|
||||
phylink_get_fixed_state(pl, &link_state);
|
||||
- phylink_mac_config(pl, &link_state);
|
||||
+ phylink_mac_config_up(pl, &link_state);
|
||||
break;
|
||||
|
||||
case MLO_AN_INBAND:
|
@ -0,0 +1,59 @@
|
||||
From 72f973f292b3eaaf451ebcd3253900d41f4ef24a Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Fri, 25 Jan 2019 17:42:51 +0000
|
||||
Subject: [PATCH] net: phylink: ensure inband AN works correctly
|
||||
|
||||
Do not update the link interface mode while the link is down to avoid
|
||||
spurious link interface changes.
|
||||
|
||||
Always call mac_config if we have a PHY to propagate the pause mode
|
||||
settings to the MAC.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 37 +++++++++++++++----------------------
|
||||
1 file changed, 15 insertions(+), 22 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -459,28 +459,21 @@ static void phylink_resolve(struct work_
|
||||
|
||||
case MLO_AN_INBAND:
|
||||
phylink_get_mac_state(pl, &link_state);
|
||||
- if (pl->phydev) {
|
||||
- bool changed = false;
|
||||
|
||||
- link_state.link = link_state.link &&
|
||||
- pl->phy_state.link;
|
||||
+ /* If we have a phy, the "up" state is the union of
|
||||
+ * both the PHY and the MAC */
|
||||
+ if (pl->phydev)
|
||||
+ link_state.link &= pl->phy_state.link;
|
||||
|
||||
- if (pl->phy_state.interface !=
|
||||
- link_state.interface) {
|
||||
- link_state.interface = pl->phy_state.interface;
|
||||
- changed = true;
|
||||
- }
|
||||
+ /* Only update if the PHY link is up */
|
||||
+ if (pl->phydev && pl->phy_state.link) {
|
||||
+ link_state.interface = pl->phy_state.interface;
|
||||
|
||||
- /* Propagate the flow control from the PHY
|
||||
- * to the MAC. Also propagate the interface
|
||||
- * if changed.
|
||||
- */
|
||||
- if (pl->phy_state.link || changed) {
|
||||
- link_state.pause |= pl->phy_state.pause;
|
||||
- phylink_resolve_flow(pl, &link_state);
|
||||
-
|
||||
- phylink_mac_config(pl, &link_state);
|
||||
- }
|
||||
+ /* If we have a PHY, we need to update with
|
||||
+ * the pause mode bits. */
|
||||
+ link_state.pause |= pl->phy_state.pause;
|
||||
+ phylink_resolve_flow(pl, &link_state);
|
||||
+ phylink_mac_config(pl, &link_state);
|
||||
}
|
||||
break;
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
From 1da223db3a0c522300b519ecbe1dc45927e28088 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Wed, 12 Sep 2018 01:53:15 +0200
|
||||
Subject: [PATCH 600/660] net: ethernet: Add helper for MACs which support asym
|
||||
pause
|
||||
|
||||
Rather than have the MAC drivers manipulate phydev members to indicate
|
||||
they support Asym Pause, add a helper function.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 13 +++++++++++++
|
||||
include/linux/phy.h | 1 +
|
||||
2 files changed, 14 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1777,6 +1777,19 @@ int phy_set_max_speed(struct phy_device
|
||||
}
|
||||
EXPORT_SYMBOL(phy_set_max_speed);
|
||||
|
||||
+/**
|
||||
+ * phy_support_asym_pause - Enable support of asym pause
|
||||
+ * @phydev: target phy_device struct
|
||||
+ *
|
||||
+ * Description: Called by the MAC to indicate is supports Asym Pause.
|
||||
+ */
|
||||
+void phy_support_asym_pause(struct phy_device *phydev)
|
||||
+{
|
||||
+ phydev->supported |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
+ phydev->advertising = phydev->supported;
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_support_asym_pause);
|
||||
+
|
||||
static void of_set_phy_supported(struct phy_device *phydev)
|
||||
{
|
||||
struct device_node *node = phydev->mdio.dev.of_node;
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1049,6 +1049,7 @@ int phy_mii_ioctl(struct phy_device *phy
|
||||
int phy_start_interrupts(struct phy_device *phydev);
|
||||
void phy_print_status(struct phy_device *phydev);
|
||||
int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
|
||||
+void phy_support_asym_pause(struct phy_device *phydev);
|
||||
|
||||
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *));
|
@ -0,0 +1,66 @@
|
||||
From ce825df56e0480a2cbb296e38976babafb57e503 Mon Sep 17 00:00:00 2001
|
||||
From: Andrew Lunn <andrew@lunn.ch>
|
||||
Date: Wed, 12 Sep 2018 01:53:17 +0200
|
||||
Subject: [PATCH 601/660] net: ethernet: Add helper for set_pauseparam for Asym
|
||||
Pause
|
||||
|
||||
ethtool can be used to enable/disable pause. Add a helper to configure
|
||||
the PHY when asym pause is supported.
|
||||
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 30 ++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 1 +
|
||||
2 files changed, 31 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -1790,6 +1790,36 @@ void phy_support_asym_pause(struct phy_d
|
||||
}
|
||||
EXPORT_SYMBOL(phy_support_asym_pause);
|
||||
|
||||
+/**
|
||||
+ * phy_set_asym_pause - Configure Pause and Asym Pause
|
||||
+ * @phydev: target phy_device struct
|
||||
+ * @rx: Receiver Pause is supported
|
||||
+ * @tx: Transmit Pause is supported
|
||||
+ *
|
||||
+ * Description: Configure advertised Pause support depending on if
|
||||
+ * transmit and receiver pause is supported. If there has been a
|
||||
+ * change in adverting, trigger a new autoneg. Generally called from
|
||||
+ * the set_pauseparam .ndo.
|
||||
+ */
|
||||
+void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx)
|
||||
+{
|
||||
+ u16 oldadv = phydev->advertising;
|
||||
+ u16 newadv = oldadv &= ~(SUPPORTED_Pause | SUPPORTED_Asym_Pause);
|
||||
+
|
||||
+ if (rx)
|
||||
+ newadv |= SUPPORTED_Pause | SUPPORTED_Asym_Pause;
|
||||
+ if (tx)
|
||||
+ newadv ^= SUPPORTED_Asym_Pause;
|
||||
+
|
||||
+ if (oldadv != newadv) {
|
||||
+ phydev->advertising = newadv;
|
||||
+
|
||||
+ if (phydev->autoneg)
|
||||
+ phy_start_aneg(phydev);
|
||||
+ }
|
||||
+}
|
||||
+EXPORT_SYMBOL(phy_set_asym_pause);
|
||||
+
|
||||
static void of_set_phy_supported(struct phy_device *phydev)
|
||||
{
|
||||
struct device_node *node = phydev->mdio.dev.of_node;
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1050,6 +1050,7 @@ int phy_start_interrupts(struct phy_devi
|
||||
void phy_print_status(struct phy_device *phydev);
|
||||
int phy_set_max_speed(struct phy_device *phydev, u32 max_speed);
|
||||
void phy_support_asym_pause(struct phy_device *phydev);
|
||||
+void phy_set_asym_pause(struct phy_device *phydev, bool rx, bool tx);
|
||||
|
||||
int phy_register_fixup(const char *bus_id, u32 phy_uid, u32 phy_uid_mask,
|
||||
int (*run)(struct phy_device *));
|
@ -0,0 +1,40 @@
|
||||
From 1541649a9dd79e9b941d399de564475e426a2d0b Mon Sep 17 00:00:00 2001
|
||||
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Date: Tue, 25 Sep 2018 11:28:45 -0700
|
||||
Subject: [PATCH 602/660] net: phy: Stop with excessive soft reset
|
||||
|
||||
While consolidating the PHY reset in phy_init_hw() an unconditionaly
|
||||
BMCR soft-reset I became quite trigger happy with those. This was later
|
||||
on deactivated for the Generic PHY driver on the premise that a prior
|
||||
software entity (e.g: bootloader) might have applied workarounds in
|
||||
commit 0878fff1f42c ("net: phy: Do not perform software reset for
|
||||
Generic PHY").
|
||||
|
||||
Since we have a hook to wire-up a soft_reset callback, just use that and
|
||||
get rid of the call to genphy_soft_reset() entirely. This speeds up
|
||||
initialization and link establishment for most PHYs out there that do
|
||||
not require a reset.
|
||||
|
||||
Fixes: 87aa9f9c61ad ("net: phy: consolidate PHY reset in phy_init_hw()")
|
||||
Tested-by: Wang, Dongsheng <dongsheng.wang@hxt-semitech.com>
|
||||
Tested-by: Chris Healy <cphealy@gmail.com>
|
||||
Tested-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Tested-by: Clemens Gruber <clemens.gruber@pqgruber.com>
|
||||
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 2 --
|
||||
1 file changed, 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -886,8 +886,6 @@ int phy_init_hw(struct phy_device *phyde
|
||||
|
||||
if (phydev->drv->soft_reset)
|
||||
ret = phydev->drv->soft_reset(phydev);
|
||||
- else
|
||||
- ret = genphy_soft_reset(phydev);
|
||||
|
||||
if (ret < 0)
|
||||
return ret;
|
@ -0,0 +1,375 @@
|
||||
From 80758d9542205cd2e9fa730067bc3888d4f5a096 Mon Sep 17 00:00:00 2001
|
||||
From: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
|
||||
Date: Wed, 6 Feb 2019 07:36:40 +0100
|
||||
Subject: [PATCH 603/660] net: phy: provide full set of accessor functions to
|
||||
MMD registers
|
||||
|
||||
This adds full set of locked and unlocked accessor functions to read and
|
||||
write PHY MMD registers and/or bitfields.
|
||||
|
||||
Set of functions exactly matches what is already available for PHY
|
||||
legacy registers.
|
||||
|
||||
Signed-off-by: Nikita Yushchenko <nikita.yoush@cogentembedded.com>
|
||||
Signed-off-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy-core.c | 116 ++++++++++++++++++++++++++++----
|
||||
include/linux/phy.h | 134 ++++++++++++++++++++++++++++++-------
|
||||
2 files changed, 214 insertions(+), 36 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy-core.c
|
||||
+++ b/drivers/net/phy/phy-core.c
|
||||
@@ -247,15 +247,15 @@ static void mmd_phy_indirect(struct mii_
|
||||
}
|
||||
|
||||
/**
|
||||
- * phy_read_mmd - Convenience function for reading a register
|
||||
+ * __phy_read_mmd - Convenience function for reading a register
|
||||
* from an MMD on a given PHY.
|
||||
* @phydev: The phy_device struct
|
||||
* @devad: The MMD to read from (0..31)
|
||||
* @regnum: The register on the MMD to read (0..65535)
|
||||
*
|
||||
- * Same rules as for phy_read();
|
||||
+ * Same rules as for __phy_read();
|
||||
*/
|
||||
-int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
|
||||
+int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
|
||||
{
|
||||
int val;
|
||||
|
||||
@@ -267,33 +267,52 @@ int phy_read_mmd(struct phy_device *phyd
|
||||
} else if (phydev->is_c45) {
|
||||
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
|
||||
|
||||
- val = mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
|
||||
+ val = __mdiobus_read(phydev->mdio.bus, phydev->mdio.addr, addr);
|
||||
} else {
|
||||
struct mii_bus *bus = phydev->mdio.bus;
|
||||
int phy_addr = phydev->mdio.addr;
|
||||
|
||||
- mutex_lock(&bus->mdio_lock);
|
||||
mmd_phy_indirect(bus, phy_addr, devad, regnum);
|
||||
|
||||
/* Read the content of the MMD's selected register */
|
||||
val = __mdiobus_read(bus, phy_addr, MII_MMD_DATA);
|
||||
- mutex_unlock(&bus->mdio_lock);
|
||||
}
|
||||
return val;
|
||||
}
|
||||
+EXPORT_SYMBOL(__phy_read_mmd);
|
||||
+
|
||||
+/**
|
||||
+ * phy_read_mmd - Convenience function for reading a register
|
||||
+ * from an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to read from
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ *
|
||||
+ * Same rules as for phy_read();
|
||||
+ */
|
||||
+int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
||||
+ ret = __phy_read_mmd(phydev, devad, regnum);
|
||||
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
EXPORT_SYMBOL(phy_read_mmd);
|
||||
|
||||
/**
|
||||
- * phy_write_mmd - Convenience function for writing a register
|
||||
+ * __phy_write_mmd - Convenience function for writing a register
|
||||
* on an MMD on a given PHY.
|
||||
* @phydev: The phy_device struct
|
||||
* @devad: The MMD to read from
|
||||
* @regnum: The register on the MMD to read
|
||||
* @val: value to write to @regnum
|
||||
*
|
||||
- * Same rules as for phy_write();
|
||||
+ * Same rules as for __phy_write();
|
||||
*/
|
||||
-int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
|
||||
+int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
|
||||
{
|
||||
int ret;
|
||||
|
||||
@@ -305,23 +324,43 @@ int phy_write_mmd(struct phy_device *phy
|
||||
} else if (phydev->is_c45) {
|
||||
u32 addr = MII_ADDR_C45 | (devad << 16) | (regnum & 0xffff);
|
||||
|
||||
- ret = mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
|
||||
- addr, val);
|
||||
+ ret = __mdiobus_write(phydev->mdio.bus, phydev->mdio.addr,
|
||||
+ addr, val);
|
||||
} else {
|
||||
struct mii_bus *bus = phydev->mdio.bus;
|
||||
int phy_addr = phydev->mdio.addr;
|
||||
|
||||
- mutex_lock(&bus->mdio_lock);
|
||||
mmd_phy_indirect(bus, phy_addr, devad, regnum);
|
||||
|
||||
/* Write the data into MMD's selected register */
|
||||
__mdiobus_write(bus, phy_addr, MII_MMD_DATA, val);
|
||||
- mutex_unlock(&bus->mdio_lock);
|
||||
|
||||
ret = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
+EXPORT_SYMBOL(__phy_write_mmd);
|
||||
+
|
||||
+/**
|
||||
+ * phy_write_mmd - Convenience function for writing a register
|
||||
+ * on an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to read from
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ * @val: value to write to @regnum
|
||||
+ *
|
||||
+ * Same rules as for phy_write();
|
||||
+ */
|
||||
+int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
||||
+ ret = __phy_write_mmd(phydev, devad, regnum, val);
|
||||
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
EXPORT_SYMBOL(phy_write_mmd);
|
||||
|
||||
/**
|
||||
@@ -371,6 +410,57 @@ int phy_modify(struct phy_device *phydev
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phy_modify);
|
||||
|
||||
+/**
|
||||
+ * __phy_modify_mmd - Convenience function for modifying a register on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * Unlocked helper function which allows a MMD register to be modified as
|
||||
+ * new register value = (old register value & ~mask) | set
|
||||
+ */
|
||||
+int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __phy_read_mmd(phydev, devad, regnum);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ ret = __phy_write_mmd(phydev, devad, regnum, (ret & ~mask) | set);
|
||||
+
|
||||
+ return ret < 0 ? ret : 0;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(__phy_modify_mmd);
|
||||
+
|
||||
+/**
|
||||
+ * phy_modify_mmd - Convenience function for modifying a register on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * NOTE: MUST NOT be called from interrupt context,
|
||||
+ * because the bus read/write functions may wait for an interrupt
|
||||
+ * to conclude the operation.
|
||||
+ */
|
||||
+int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
||||
+ ret = __phy_modify_mmd(phydev, devad, regnum, mask, set);
|
||||
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(phy_modify_mmd);
|
||||
+
|
||||
static int __phy_read_page(struct phy_device *phydev)
|
||||
{
|
||||
return phydev->drv->read_page(phydev);
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -695,17 +695,6 @@ size_t phy_speeds(unsigned int *speeds,
|
||||
void phy_resolve_aneg_linkmode(struct phy_device *phydev);
|
||||
|
||||
/**
|
||||
- * phy_read_mmd - Convenience function for reading a register
|
||||
- * from an MMD on a given PHY.
|
||||
- * @phydev: The phy_device struct
|
||||
- * @devad: The MMD to read from
|
||||
- * @regnum: The register on the MMD to read
|
||||
- *
|
||||
- * Same rules as for phy_read();
|
||||
- */
|
||||
-int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
|
||||
-
|
||||
-/**
|
||||
* phy_read - Convenience function for reading a given PHY register
|
||||
* @phydev: the phy_device struct
|
||||
* @regnum: register number to read
|
||||
@@ -760,9 +749,60 @@ static inline int __phy_write(struct phy
|
||||
val);
|
||||
}
|
||||
|
||||
+/**
|
||||
+ * phy_read_mmd - Convenience function for reading a register
|
||||
+ * from an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to read from
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ *
|
||||
+ * Same rules as for phy_read();
|
||||
+ */
|
||||
+int phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
|
||||
+
|
||||
+/**
|
||||
+ * __phy_read_mmd - Convenience function for reading a register
|
||||
+ * from an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to read from
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ *
|
||||
+ * Same rules as for __phy_read();
|
||||
+ */
|
||||
+int __phy_read_mmd(struct phy_device *phydev, int devad, u32 regnum);
|
||||
+
|
||||
+/**
|
||||
+ * phy_write_mmd - Convenience function for writing a register
|
||||
+ * on an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to write to
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ * @val: value to write to @regnum
|
||||
+ *
|
||||
+ * Same rules as for phy_write();
|
||||
+ */
|
||||
+int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
|
||||
+
|
||||
+/**
|
||||
+ * __phy_write_mmd - Convenience function for writing a register
|
||||
+ * on an MMD on a given PHY.
|
||||
+ * @phydev: The phy_device struct
|
||||
+ * @devad: The MMD to write to
|
||||
+ * @regnum: The register on the MMD to read
|
||||
+ * @val: value to write to @regnum
|
||||
+ *
|
||||
+ * Same rules as for __phy_write();
|
||||
+ */
|
||||
+int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
|
||||
+
|
||||
int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
|
||||
int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
|
||||
|
||||
+int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set);
|
||||
+int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set);
|
||||
+
|
||||
/**
|
||||
* __phy_set_bits - Convenience function for setting bits in a PHY register
|
||||
* @phydev: the phy_device struct
|
||||
@@ -813,6 +853,66 @@ static inline int phy_clear_bits(struct
|
||||
}
|
||||
|
||||
/**
|
||||
+ * __phy_set_bits_mmd - Convenience function for setting bits in a register
|
||||
+ * on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @val: bits to set
|
||||
+ *
|
||||
+ * The caller must have taken the MDIO bus lock.
|
||||
+ */
|
||||
+static inline int __phy_set_bits_mmd(struct phy_device *phydev, int devad,
|
||||
+ u32 regnum, u16 val)
|
||||
+{
|
||||
+ return __phy_modify_mmd(phydev, devad, regnum, 0, val);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * __phy_clear_bits_mmd - Convenience function for clearing bits in a register
|
||||
+ * on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @val: bits to clear
|
||||
+ *
|
||||
+ * The caller must have taken the MDIO bus lock.
|
||||
+ */
|
||||
+static inline int __phy_clear_bits_mmd(struct phy_device *phydev, int devad,
|
||||
+ u32 regnum, u16 val)
|
||||
+{
|
||||
+ return __phy_modify_mmd(phydev, devad, regnum, val, 0);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * phy_set_bits_mmd - Convenience function for setting bits in a register
|
||||
+ * on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @val: bits to set
|
||||
+ */
|
||||
+static inline int phy_set_bits_mmd(struct phy_device *phydev, int devad,
|
||||
+ u32 regnum, u16 val)
|
||||
+{
|
||||
+ return phy_modify_mmd(phydev, devad, regnum, 0, val);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * phy_clear_bits_mmd - Convenience function for clearing bits in a register
|
||||
+ * on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @val: bits to clear
|
||||
+ */
|
||||
+static inline int phy_clear_bits_mmd(struct phy_device *phydev, int devad,
|
||||
+ u32 regnum, u16 val)
|
||||
+{
|
||||
+ return phy_modify_mmd(phydev, devad, regnum, val, 0);
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
* phy_interrupt_is_valid - Convenience function for testing a given PHY irq
|
||||
* @phydev: the phy_device struct
|
||||
*
|
||||
@@ -888,18 +988,6 @@ static inline bool phy_is_pseudo_fixed_l
|
||||
return phydev->is_pseudo_fixed_link;
|
||||
}
|
||||
|
||||
-/**
|
||||
- * phy_write_mmd - Convenience function for writing a register
|
||||
- * on an MMD on a given PHY.
|
||||
- * @phydev: The phy_device struct
|
||||
- * @devad: The MMD to read from
|
||||
- * @regnum: The register on the MMD to read
|
||||
- * @val: value to write to @regnum
|
||||
- *
|
||||
- * Same rules as for phy_write();
|
||||
- */
|
||||
-int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
|
||||
-
|
||||
int phy_save_page(struct phy_device *phydev);
|
||||
int phy_select_page(struct phy_device *phydev, int page);
|
||||
int phy_restore_page(struct phy_device *phydev, int oldpage, int ret);
|
@ -0,0 +1,217 @@
|
||||
From c1e3f753f6b85d7636024159bb78f764e09492f1 Mon Sep 17 00:00:00 2001
|
||||
From: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Date: Sun, 10 Feb 2019 19:57:56 +0100
|
||||
Subject: [PATCH 604/660] net: phy: add register modifying helpers returning 1
|
||||
on change
|
||||
|
||||
When modifying registers there are scenarios where we need to know
|
||||
whether the register content actually changed. This patch adds
|
||||
new helpers to not break users of the current ones, phy_modify() etc.
|
||||
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy-core.c | 127 ++++++++++++++++++++++++++++++++++---
|
||||
include/linux/phy.h | 12 +++-
|
||||
2 files changed, 128 insertions(+), 11 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy-core.c
|
||||
+++ b/drivers/net/phy/phy-core.c
|
||||
@@ -364,7 +364,7 @@ int phy_write_mmd(struct phy_device *phy
|
||||
EXPORT_SYMBOL(phy_write_mmd);
|
||||
|
||||
/**
|
||||
- * __phy_modify() - Convenience function for modifying a PHY register
|
||||
+ * __phy_modify_changed() - Convenience function for modifying a PHY register
|
||||
* @phydev: a pointer to a &struct phy_device
|
||||
* @regnum: register number
|
||||
* @mask: bit mask of bits to clear
|
||||
@@ -372,16 +372,69 @@ EXPORT_SYMBOL(phy_write_mmd);
|
||||
*
|
||||
* Unlocked helper function which allows a PHY register to be modified as
|
||||
* new register value = (old register value & ~mask) | set
|
||||
+ *
|
||||
+ * Returns negative errno, 0 if there was no change, and 1 in case of change
|
||||
*/
|
||||
-int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
|
||||
+int __phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
|
||||
+ u16 set)
|
||||
{
|
||||
- int ret;
|
||||
+ int new, ret;
|
||||
|
||||
ret = __phy_read(phydev, regnum);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = __phy_write(phydev, regnum, (ret & ~mask) | set);
|
||||
+ new = (ret & ~mask) | set;
|
||||
+ if (new == ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = __phy_write(phydev, regnum, new);
|
||||
+
|
||||
+ return ret < 0 ? ret : 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(__phy_modify_changed);
|
||||
+
|
||||
+/**
|
||||
+ * phy_modify_changed - Function for modifying a PHY register
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * NOTE: MUST NOT be called from interrupt context,
|
||||
+ * because the bus read/write functions may wait for an interrupt
|
||||
+ * to conclude the operation.
|
||||
+ *
|
||||
+ * Returns negative errno, 0 if there was no change, and 1 in case of change
|
||||
+ */
|
||||
+int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
||||
+ ret = __phy_modify_changed(phydev, regnum, mask, set);
|
||||
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(phy_modify_changed);
|
||||
+
|
||||
+/**
|
||||
+ * __phy_modify - Convenience function for modifying a PHY register
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * NOTE: MUST NOT be called from interrupt context,
|
||||
+ * because the bus read/write functions may wait for an interrupt
|
||||
+ * to conclude the operation.
|
||||
+ */
|
||||
+int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __phy_modify_changed(phydev, regnum, mask, set);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
@@ -411,7 +464,7 @@ int phy_modify(struct phy_device *phydev
|
||||
EXPORT_SYMBOL_GPL(phy_modify);
|
||||
|
||||
/**
|
||||
- * __phy_modify_mmd - Convenience function for modifying a register on MMD
|
||||
+ * __phy_modify_mmd_changed - Function for modifying a register on MMD
|
||||
* @phydev: the phy_device struct
|
||||
* @devad: the MMD containing register to modify
|
||||
* @regnum: register number to modify
|
||||
@@ -420,17 +473,73 @@ EXPORT_SYMBOL_GPL(phy_modify);
|
||||
*
|
||||
* Unlocked helper function which allows a MMD register to be modified as
|
||||
* new register value = (old register value & ~mask) | set
|
||||
+ *
|
||||
+ * Returns negative errno, 0 if there was no change, and 1 in case of change
|
||||
*/
|
||||
-int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
- u16 mask, u16 set)
|
||||
+int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set)
|
||||
{
|
||||
- int ret;
|
||||
+ int new, ret;
|
||||
|
||||
ret = __phy_read_mmd(phydev, devad, regnum);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
- ret = __phy_write_mmd(phydev, devad, regnum, (ret & ~mask) | set);
|
||||
+ new = (ret & ~mask) | set;
|
||||
+ if (new == ret)
|
||||
+ return 0;
|
||||
+
|
||||
+ ret = __phy_write_mmd(phydev, devad, regnum, new);
|
||||
+
|
||||
+ return ret < 0 ? ret : 1;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(__phy_modify_mmd_changed);
|
||||
+
|
||||
+/**
|
||||
+ * phy_modify_mmd_changed - Function for modifying a register on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * NOTE: MUST NOT be called from interrupt context,
|
||||
+ * because the bus read/write functions may wait for an interrupt
|
||||
+ * to conclude the operation.
|
||||
+ *
|
||||
+ * Returns negative errno, 0 if there was no change, and 1 in case of change
|
||||
+ */
|
||||
+int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ mutex_lock(&phydev->mdio.bus->mdio_lock);
|
||||
+ ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
|
||||
+ mutex_unlock(&phydev->mdio.bus->mdio_lock);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(phy_modify_mmd_changed);
|
||||
+
|
||||
+/**
|
||||
+ * __phy_modify_mmd - Convenience function for modifying a register on MMD
|
||||
+ * @phydev: the phy_device struct
|
||||
+ * @devad: the MMD containing register to modify
|
||||
+ * @regnum: register number to modify
|
||||
+ * @mask: bit mask of bits to clear
|
||||
+ * @set: new value of bits set in mask to write to @regnum
|
||||
+ *
|
||||
+ * NOTE: MUST NOT be called from interrupt context,
|
||||
+ * because the bus read/write functions may wait for an interrupt
|
||||
+ * to conclude the operation.
|
||||
+ */
|
||||
+int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set)
|
||||
+{
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = __phy_modify_mmd_changed(phydev, devad, regnum, mask, set);
|
||||
|
||||
return ret < 0 ? ret : 0;
|
||||
}
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -795,13 +795,21 @@ int phy_write_mmd(struct phy_device *phy
|
||||
*/
|
||||
int __phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val);
|
||||
|
||||
+int __phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
|
||||
+ u16 set);
|
||||
+int phy_modify_changed(struct phy_device *phydev, u32 regnum, u16 mask,
|
||||
+ u16 set);
|
||||
int __phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
|
||||
int phy_modify(struct phy_device *phydev, u32 regnum, u16 mask, u16 set);
|
||||
|
||||
+int __phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set);
|
||||
+int phy_modify_mmd_changed(struct phy_device *phydev, int devad, u32 regnum,
|
||||
+ u16 mask, u16 set);
|
||||
int __phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
- u16 mask, u16 set);
|
||||
+ u16 mask, u16 set);
|
||||
int phy_modify_mmd(struct phy_device *phydev, int devad, u32 regnum,
|
||||
- u16 mask, u16 set);
|
||||
+ u16 mask, u16 set);
|
||||
|
||||
/**
|
||||
* __phy_set_bits - Convenience function for setting bits in a PHY register
|
@ -0,0 +1,64 @@
|
||||
From 2c3db705737cf52d7d24c993f0889b25b956c718 Mon Sep 17 00:00:00 2001
|
||||
From: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Date: Mon, 18 Feb 2019 21:27:18 +0100
|
||||
Subject: [PATCH 605/660] net: phy: add genphy_c45_check_and_restart_aneg
|
||||
|
||||
This function will be used by config_aneg callback implementations of
|
||||
PHY drivers and allows to reduce boilerplate code.
|
||||
|
||||
Signed-off-by: Heiner Kallweit <hkallweit1@gmail.com>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phy-c45.c | 30 ++++++++++++++++++++++++++++++
|
||||
include/linux/phy.h | 1 +
|
||||
2 files changed, 31 insertions(+)
|
||||
|
||||
--- a/drivers/net/phy/phy-c45.c
|
||||
+++ b/drivers/net/phy/phy-c45.c
|
||||
@@ -110,6 +110,36 @@ int genphy_c45_restart_aneg(struct phy_d
|
||||
EXPORT_SYMBOL_GPL(genphy_c45_restart_aneg);
|
||||
|
||||
/**
|
||||
+ * genphy_c45_check_and_restart_aneg - Enable and restart auto-negotiation
|
||||
+ * @phydev: target phy_device struct
|
||||
+ * @restart: whether aneg restart is requested
|
||||
+ *
|
||||
+ * This assumes that the auto-negotiation MMD is present.
|
||||
+ *
|
||||
+ * Check, and restart auto-negotiation if needed.
|
||||
+ */
|
||||
+int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart)
|
||||
+{
|
||||
+ int ret = 0;
|
||||
+
|
||||
+ if (!restart) {
|
||||
+ /* Configure and restart aneg if it wasn't set before */
|
||||
+ ret = phy_read_mmd(phydev, MDIO_MMD_AN, MDIO_CTRL1);
|
||||
+ if (ret < 0)
|
||||
+ return ret;
|
||||
+
|
||||
+ if (!(ret & MDIO_AN_CTRL1_ENABLE))
|
||||
+ restart = true;
|
||||
+ }
|
||||
+
|
||||
+ if (restart)
|
||||
+ ret = genphy_c45_restart_aneg(phydev);
|
||||
+
|
||||
+ return ret;
|
||||
+}
|
||||
+EXPORT_SYMBOL_GPL(genphy_c45_check_and_restart_aneg);
|
||||
+
|
||||
+/**
|
||||
* genphy_c45_aneg_done - return auto-negotiation complete status
|
||||
* @phydev: target phy_device struct
|
||||
*
|
||||
--- a/include/linux/phy.h
|
||||
+++ b/include/linux/phy.h
|
||||
@@ -1098,6 +1098,7 @@ int genphy_write_mmd_unsupported(struct
|
||||
|
||||
/* Clause 45 PHY */
|
||||
int genphy_c45_restart_aneg(struct phy_device *phydev);
|
||||
+int genphy_c45_check_and_restart_aneg(struct phy_device *phydev, bool restart);
|
||||
int genphy_c45_aneg_done(struct phy_device *phydev);
|
||||
int genphy_c45_read_link(struct phy_device *phydev, u32 mmd_mask);
|
||||
int genphy_c45_read_lpa(struct phy_device *phydev);
|
@ -0,0 +1,59 @@
|
||||
From 4c4323084e9a67210c8d269dceba1be99356c414 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 28 May 2019 10:57:18 +0100
|
||||
Subject: [PATCH 606/660] net: phylink: remove netdev from phylink mii ioctl
|
||||
emulation
|
||||
|
||||
The netdev used in the phylink ioctl emulation is never used, so let's
|
||||
remove it.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 12 ++++--------
|
||||
1 file changed, 4 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1360,8 +1360,8 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_set_ee
|
||||
*
|
||||
* FIXME: should deal with negotiation state too.
|
||||
*/
|
||||
-static int phylink_mii_emul_read(struct net_device *ndev, unsigned int reg,
|
||||
- struct phylink_link_state *state, bool aneg)
|
||||
+static int phylink_mii_emul_read(unsigned int reg,
|
||||
+ struct phylink_link_state *state)
|
||||
{
|
||||
struct fixed_phy_status fs;
|
||||
int val;
|
||||
@@ -1376,8 +1376,6 @@ static int phylink_mii_emul_read(struct
|
||||
if (reg == MII_BMSR) {
|
||||
if (!state->an_complete)
|
||||
val &= ~BMSR_ANEGCOMPLETE;
|
||||
- if (!aneg)
|
||||
- val &= ~BMSR_ANEGCAPABLE;
|
||||
}
|
||||
return val;
|
||||
}
|
||||
@@ -1473,8 +1471,7 @@ static int phylink_mii_read(struct phyli
|
||||
case MLO_AN_FIXED:
|
||||
if (phy_id == 0) {
|
||||
phylink_get_fixed_state(pl, &state);
|
||||
- val = phylink_mii_emul_read(pl->netdev, reg, &state,
|
||||
- true);
|
||||
+ val = phylink_mii_emul_read(reg, &state);
|
||||
}
|
||||
break;
|
||||
|
||||
@@ -1487,8 +1484,7 @@ static int phylink_mii_read(struct phyli
|
||||
if (val < 0)
|
||||
return val;
|
||||
|
||||
- val = phylink_mii_emul_read(pl->netdev, reg, &state,
|
||||
- true);
|
||||
+ val = phylink_mii_emul_read(reg, &state);
|
||||
}
|
||||
break;
|
||||
}
|
@ -0,0 +1,90 @@
|
||||
From cba0aba37d2228556e0d1f776d403435868cdbfa Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 28 May 2019 10:57:23 +0100
|
||||
Subject: [PATCH 607/660] net: phylink: support for link gpio interrupt
|
||||
|
||||
Add support for using GPIO interrupts with a fixed-link GPIO rather than
|
||||
polling the GPIO every second and invoking the phylink resolution. This
|
||||
avoids unnecessary calls to mac_config().
|
||||
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 36 ++++++++++++++++++++++++++++++++----
|
||||
1 file changed, 32 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -59,6 +59,7 @@ struct phylink {
|
||||
phy_interface_t cur_interface;
|
||||
|
||||
struct gpio_desc *link_gpio;
|
||||
+ unsigned int link_irq;
|
||||
struct timer_list link_poll;
|
||||
void (*get_fixed_state)(struct net_device *dev,
|
||||
struct phylink_link_state *s);
|
||||
@@ -645,7 +646,7 @@ void phylink_destroy(struct phylink *pl)
|
||||
{
|
||||
if (pl->sfp_bus)
|
||||
sfp_unregister_upstream(pl->sfp_bus);
|
||||
- if (!IS_ERR_OR_NULL(pl->link_gpio))
|
||||
+ if (pl->link_gpio)
|
||||
gpiod_put(pl->link_gpio);
|
||||
|
||||
cancel_work_sync(&pl->resolve);
|
||||
@@ -912,6 +913,15 @@ void phylink_mac_change(struct phylink *
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_mac_change);
|
||||
|
||||
+static irqreturn_t phylink_link_handler(int irq, void *data)
|
||||
+{
|
||||
+ struct phylink *pl = data;
|
||||
+
|
||||
+ phylink_run_resolve(pl);
|
||||
+
|
||||
+ return IRQ_HANDLED;
|
||||
+}
|
||||
+
|
||||
/**
|
||||
* phylink_start() - start a phylink instance
|
||||
* @pl: a pointer to a &struct phylink returned from phylink_create()
|
||||
@@ -947,7 +957,22 @@ void phylink_start(struct phylink *pl)
|
||||
clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
|
||||
phylink_run_resolve(pl);
|
||||
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
|
||||
+ if (pl->link_an_mode == MLO_AN_FIXED && pl->link_gpio) {
|
||||
+ int irq = gpiod_to_irq(pl->link_gpio);
|
||||
+
|
||||
+ if (irq > 0) {
|
||||
+ if (!request_irq(irq, phylink_link_handler,
|
||||
+ IRQF_TRIGGER_RISING |
|
||||
+ IRQF_TRIGGER_FALLING,
|
||||
+ "netdev link", pl))
|
||||
+ pl->link_irq = irq;
|
||||
+ else
|
||||
+ irq = 0;
|
||||
+ }
|
||||
+ if (irq <= 0)
|
||||
+ mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
+ }
|
||||
+ if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
|
||||
mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
if (pl->sfp_bus)
|
||||
sfp_upstream_start(pl->sfp_bus);
|
||||
@@ -973,8 +998,11 @@ void phylink_stop(struct phylink *pl)
|
||||
phy_stop(pl->phydev);
|
||||
if (pl->sfp_bus)
|
||||
sfp_upstream_stop(pl->sfp_bus);
|
||||
- if (pl->link_an_mode == MLO_AN_FIXED && !IS_ERR(pl->link_gpio))
|
||||
- del_timer_sync(&pl->link_poll);
|
||||
+ del_timer_sync(&pl->link_poll);
|
||||
+ if (pl->link_irq) {
|
||||
+ free_irq(pl->link_irq, pl);
|
||||
+ pl->link_irq = 0;
|
||||
+ }
|
||||
|
||||
phylink_run_resolve_and_disable(pl, PHYLINK_DISABLE_STOPPED);
|
||||
}
|
@ -0,0 +1,77 @@
|
||||
From eb5df3d026824832831376bbdf04e01a52776eea Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 28 May 2019 10:57:29 +0100
|
||||
Subject: [PATCH 608/660] net: phy: allow Clause 45 access via mii ioctl
|
||||
|
||||
Allow userspace to generate Clause 45 MII access cycles via phylib.
|
||||
This is useful for tools such as mii-diag to be able to inspect Clause
|
||||
45 PHYs.
|
||||
|
||||
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy.c | 33 ++++++++++++++++++++++++---------
|
||||
1 file changed, 24 insertions(+), 9 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy.c
|
||||
+++ b/drivers/net/phy/phy.c
|
||||
@@ -397,6 +397,7 @@ int phy_mii_ioctl(struct phy_device *phy
|
||||
struct mii_ioctl_data *mii_data = if_mii(ifr);
|
||||
u16 val = mii_data->val_in;
|
||||
bool change_autoneg = false;
|
||||
+ int prtad, devad;
|
||||
|
||||
switch (cmd) {
|
||||
case SIOCGMIIPHY:
|
||||
@@ -404,14 +405,29 @@ int phy_mii_ioctl(struct phy_device *phy
|
||||
/* fall through */
|
||||
|
||||
case SIOCGMIIREG:
|
||||
- mii_data->val_out = mdiobus_read(phydev->mdio.bus,
|
||||
- mii_data->phy_id,
|
||||
- mii_data->reg_num);
|
||||
+ if (mdio_phy_id_is_c45(mii_data->phy_id)) {
|
||||
+ prtad = mdio_phy_id_prtad(mii_data->phy_id);
|
||||
+ devad = mdio_phy_id_devad(mii_data->phy_id);
|
||||
+ devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
|
||||
+ } else {
|
||||
+ prtad = mii_data->phy_id;
|
||||
+ devad = mii_data->reg_num;
|
||||
+ }
|
||||
+ mii_data->val_out = mdiobus_read(phydev->mdio.bus, prtad,
|
||||
+ devad);
|
||||
return 0;
|
||||
|
||||
case SIOCSMIIREG:
|
||||
- if (mii_data->phy_id == phydev->mdio.addr) {
|
||||
- switch (mii_data->reg_num) {
|
||||
+ if (mdio_phy_id_is_c45(mii_data->phy_id)) {
|
||||
+ prtad = mdio_phy_id_prtad(mii_data->phy_id);
|
||||
+ devad = mdio_phy_id_devad(mii_data->phy_id);
|
||||
+ devad = MII_ADDR_C45 | devad << 16 | mii_data->reg_num;
|
||||
+ } else {
|
||||
+ prtad = mii_data->phy_id;
|
||||
+ devad = mii_data->reg_num;
|
||||
+ }
|
||||
+ if (prtad == phydev->mdio.addr) {
|
||||
+ switch (devad) {
|
||||
case MII_BMCR:
|
||||
if ((val & (BMCR_RESET | BMCR_ANENABLE)) == 0) {
|
||||
if (phydev->autoneg == AUTONEG_ENABLE)
|
||||
@@ -443,11 +459,10 @@ int phy_mii_ioctl(struct phy_device *phy
|
||||
}
|
||||
}
|
||||
|
||||
- mdiobus_write(phydev->mdio.bus, mii_data->phy_id,
|
||||
- mii_data->reg_num, val);
|
||||
+ mdiobus_write(phydev->mdio.bus, prtad, devad, val);
|
||||
|
||||
- if (mii_data->phy_id == phydev->mdio.addr &&
|
||||
- mii_data->reg_num == MII_BMCR &&
|
||||
+ if (prtad == phydev->mdio.addr &&
|
||||
+ devad == MII_BMCR &&
|
||||
val & BMCR_RESET)
|
||||
return phy_init_hw(phydev);
|
||||
|
@ -0,0 +1,94 @@
|
||||
From aeabfaa63285470e81fa341e14f92d68880aa160 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 28 May 2019 10:57:34 +0100
|
||||
Subject: [PATCH 609/660] net: sfp: add mandatory attach/detach methods for sfp
|
||||
buses
|
||||
|
||||
Add attach and detach methods for SFP buses, which will allow us to get
|
||||
rid of the netdev storage in sfp-bus.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 16 ++++++++++++++++
|
||||
drivers/net/phy/sfp-bus.c | 4 ++--
|
||||
include/linux/sfp.h | 6 ++++++
|
||||
3 files changed, 24 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1615,6 +1615,20 @@ int phylink_mii_ioctl(struct phylink *pl
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_mii_ioctl);
|
||||
|
||||
+static void phylink_sfp_attach(void *upstream, struct sfp_bus *bus)
|
||||
+{
|
||||
+ struct phylink *pl = upstream;
|
||||
+
|
||||
+ pl->netdev->sfp_bus = bus;
|
||||
+}
|
||||
+
|
||||
+static void phylink_sfp_detach(void *upstream, struct sfp_bus *bus)
|
||||
+{
|
||||
+ struct phylink *pl = upstream;
|
||||
+
|
||||
+ pl->netdev->sfp_bus = NULL;
|
||||
+}
|
||||
+
|
||||
static int phylink_sfp_module_insert(void *upstream,
|
||||
const struct sfp_eeprom_id *id)
|
||||
{
|
||||
@@ -1733,6 +1747,8 @@ static void phylink_sfp_disconnect_phy(v
|
||||
}
|
||||
|
||||
static const struct sfp_upstream_ops sfp_phylink_ops = {
|
||||
+ .attach = phylink_sfp_attach,
|
||||
+ .detach = phylink_sfp_detach,
|
||||
.module_insert = phylink_sfp_module_insert,
|
||||
.link_up = phylink_sfp_link_up,
|
||||
.link_down = phylink_sfp_link_down,
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -350,7 +350,7 @@ static int sfp_register_bus(struct sfp_b
|
||||
bus->socket_ops->attach(bus->sfp);
|
||||
if (bus->started)
|
||||
bus->socket_ops->start(bus->sfp);
|
||||
- bus->netdev->sfp_bus = bus;
|
||||
+ bus->upstream_ops->attach(bus->upstream, bus);
|
||||
bus->registered = true;
|
||||
return 0;
|
||||
}
|
||||
@@ -359,8 +359,8 @@ static void sfp_unregister_bus(struct sf
|
||||
{
|
||||
const struct sfp_upstream_ops *ops = bus->upstream_ops;
|
||||
|
||||
- bus->netdev->sfp_bus = NULL;
|
||||
if (bus->registered) {
|
||||
+ bus->upstream_ops->detach(bus->upstream, bus);
|
||||
if (bus->started)
|
||||
bus->socket_ops->stop(bus->sfp);
|
||||
bus->socket_ops->detach(bus->sfp);
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -469,6 +469,10 @@ struct sfp_bus;
|
||||
|
||||
/**
|
||||
* struct sfp_upstream_ops - upstream operations structure
|
||||
+ * @attach: called when the sfp socket driver is bound to the upstream
|
||||
+ * (mandatory).
|
||||
+ * @detach: called when the sfp socket driver is unbound from the upstream
|
||||
+ * (mandatory).
|
||||
* @module_insert: called after a module has been detected to determine
|
||||
* whether the module is supported for the upstream device.
|
||||
* @module_remove: called after the module has been removed.
|
||||
@@ -481,6 +485,8 @@ struct sfp_bus;
|
||||
* been removed.
|
||||
*/
|
||||
struct sfp_upstream_ops {
|
||||
+ void (*attach)(void *priv, struct sfp_bus *bus);
|
||||
+ void (*detach)(void *priv, struct sfp_bus *bus);
|
||||
int (*module_insert)(void *priv, const struct sfp_eeprom_id *id);
|
||||
void (*module_remove)(void *priv);
|
||||
void (*link_down)(void *priv);
|
@ -0,0 +1,118 @@
|
||||
From 60d756717d772be90d07a07cd2cc140c76da3e4a Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 28 May 2019 10:57:39 +0100
|
||||
Subject: [PATCH 610/660] net: sfp: remove sfp-bus use of netdevs
|
||||
|
||||
The sfp-bus code now no longer has any use for the network device
|
||||
structure, so remove its use.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 3 +--
|
||||
drivers/net/phy/sfp-bus.c | 10 +++-------
|
||||
include/linux/sfp.h | 6 ++----
|
||||
3 files changed, 6 insertions(+), 13 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -555,8 +555,7 @@ static int phylink_register_sfp(struct p
|
||||
return ret;
|
||||
}
|
||||
|
||||
- pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl->netdev, pl,
|
||||
- &sfp_phylink_ops);
|
||||
+ pl->sfp_bus = sfp_register_upstream(ref.fwnode, pl, &sfp_phylink_ops);
|
||||
if (!pl->sfp_bus)
|
||||
return -ENOMEM;
|
||||
|
||||
--- a/drivers/net/phy/sfp-bus.c
|
||||
+++ b/drivers/net/phy/sfp-bus.c
|
||||
@@ -23,7 +23,6 @@ struct sfp_bus {
|
||||
|
||||
const struct sfp_upstream_ops *upstream_ops;
|
||||
void *upstream;
|
||||
- struct net_device *netdev;
|
||||
struct phy_device *phydev;
|
||||
|
||||
bool registered;
|
||||
@@ -442,13 +441,11 @@ static void sfp_upstream_clear(struct sf
|
||||
{
|
||||
bus->upstream_ops = NULL;
|
||||
bus->upstream = NULL;
|
||||
- bus->netdev = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* sfp_register_upstream() - Register the neighbouring device
|
||||
* @fwnode: firmware node for the SFP bus
|
||||
- * @ndev: network device associated with the interface
|
||||
* @upstream: the upstream private data
|
||||
* @ops: the upstream's &struct sfp_upstream_ops
|
||||
*
|
||||
@@ -459,7 +456,7 @@ static void sfp_upstream_clear(struct sf
|
||||
* On error, returns %NULL.
|
||||
*/
|
||||
struct sfp_bus *sfp_register_upstream(struct fwnode_handle *fwnode,
|
||||
- struct net_device *ndev, void *upstream,
|
||||
+ void *upstream,
|
||||
const struct sfp_upstream_ops *ops)
|
||||
{
|
||||
struct sfp_bus *bus = sfp_bus_get(fwnode);
|
||||
@@ -469,7 +466,6 @@ struct sfp_bus *sfp_register_upstream(st
|
||||
rtnl_lock();
|
||||
bus->upstream_ops = ops;
|
||||
bus->upstream = upstream;
|
||||
- bus->netdev = ndev;
|
||||
|
||||
if (bus->sfp) {
|
||||
ret = sfp_register_bus(bus);
|
||||
@@ -591,7 +587,7 @@ struct sfp_bus *sfp_register_socket(stru
|
||||
bus->sfp = sfp;
|
||||
bus->socket_ops = ops;
|
||||
|
||||
- if (bus->netdev) {
|
||||
+ if (bus->upstream_ops) {
|
||||
ret = sfp_register_bus(bus);
|
||||
if (ret)
|
||||
sfp_socket_clear(bus);
|
||||
@@ -611,7 +607,7 @@ EXPORT_SYMBOL_GPL(sfp_register_socket);
|
||||
void sfp_unregister_socket(struct sfp_bus *bus)
|
||||
{
|
||||
rtnl_lock();
|
||||
- if (bus->netdev)
|
||||
+ if (bus->upstream_ops)
|
||||
sfp_unregister_bus(bus);
|
||||
sfp_socket_clear(bus);
|
||||
rtnl_unlock();
|
||||
--- a/include/linux/sfp.h
|
||||
+++ b/include/linux/sfp.h
|
||||
@@ -464,7 +464,6 @@ enum {
|
||||
struct fwnode_handle;
|
||||
struct ethtool_eeprom;
|
||||
struct ethtool_modinfo;
|
||||
-struct net_device;
|
||||
struct sfp_bus;
|
||||
|
||||
/**
|
||||
@@ -510,7 +509,7 @@ int sfp_get_module_eeprom(struct sfp_bus
|
||||
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,
|
||||
- struct net_device *ndev, void *upstream,
|
||||
+ void *upstream,
|
||||
const struct sfp_upstream_ops *ops);
|
||||
void sfp_unregister_upstream(struct sfp_bus *bus);
|
||||
#else
|
||||
@@ -555,8 +554,7 @@ static inline void sfp_upstream_stop(str
|
||||
}
|
||||
|
||||
static inline struct sfp_bus *sfp_register_upstream(
|
||||
- struct fwnode_handle *fwnode,
|
||||
- struct net_device *ndev, void *upstream,
|
||||
+ struct fwnode_handle *fwnode, void *upstream,
|
||||
const struct sfp_upstream_ops *ops)
|
||||
{
|
||||
return (struct sfp_bus *)-1;
|
@ -0,0 +1,84 @@
|
||||
From 8ac1d3e5cf7d277769ba3403d99f643fab1e3fae Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Sat, 23 Nov 2019 14:19:54 +0000
|
||||
Subject: [PATCH 611/660] net: phylink: avoid reducing support mask
|
||||
|
||||
Avoid reducing the support mask as a result of the interface type
|
||||
selected for SFP modules, or when setting the link settings through
|
||||
ethtool - this should only change when the supported link modes of
|
||||
the hardware combination change.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 13 +++++++++----
|
||||
1 file changed, 9 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1137,6 +1137,7 @@ EXPORT_SYMBOL_GPL(phylink_ethtool_ksetti
|
||||
int phylink_ethtool_ksettings_set(struct phylink *pl,
|
||||
const struct ethtool_link_ksettings *kset)
|
||||
{
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support);
|
||||
struct ethtool_link_ksettings our_kset;
|
||||
struct phylink_link_state config;
|
||||
int ret;
|
||||
@@ -1147,11 +1148,12 @@ int phylink_ethtool_ksettings_set(struct
|
||||
kset->base.autoneg != AUTONEG_ENABLE)
|
||||
return -EINVAL;
|
||||
|
||||
+ linkmode_copy(support, pl->supported);
|
||||
config = pl->link_config;
|
||||
|
||||
/* Mask out unsupported advertisements */
|
||||
linkmode_and(config.advertising, kset->link_modes.advertising,
|
||||
- pl->supported);
|
||||
+ support);
|
||||
|
||||
/* FIXME: should we reject autoneg if phy/mac does not support it? */
|
||||
if (kset->base.autoneg == AUTONEG_DISABLE) {
|
||||
@@ -1161,7 +1163,7 @@ int phylink_ethtool_ksettings_set(struct
|
||||
* duplex.
|
||||
*/
|
||||
s = phy_lookup_setting(kset->base.speed, kset->base.duplex,
|
||||
- pl->supported,
|
||||
+ support,
|
||||
__ETHTOOL_LINK_MODE_MASK_NBITS, false);
|
||||
if (!s)
|
||||
return -EINVAL;
|
||||
@@ -1191,7 +1193,7 @@ int phylink_ethtool_ksettings_set(struct
|
||||
__set_bit(ETHTOOL_LINK_MODE_Autoneg_BIT, config.advertising);
|
||||
}
|
||||
|
||||
- if (phylink_validate(pl, pl->supported, &config))
|
||||
+ if (phylink_validate(pl, support, &config))
|
||||
return -EINVAL;
|
||||
|
||||
/* If autonegotiation is enabled, we must have an advertisement */
|
||||
@@ -1633,6 +1635,7 @@ static int phylink_sfp_module_insert(voi
|
||||
{
|
||||
struct phylink *pl = upstream;
|
||||
__ETHTOOL_DECLARE_LINK_MODE_MASK(support) = { 0, };
|
||||
+ __ETHTOOL_DECLARE_LINK_MODE_MASK(support1);
|
||||
struct phylink_link_state config;
|
||||
phy_interface_t iface;
|
||||
int ret = 0;
|
||||
@@ -1660,6 +1663,8 @@ static int phylink_sfp_module_insert(voi
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ linkmode_copy(support1, support);
|
||||
+
|
||||
iface = sfp_select_interface(pl->sfp_bus, id, config.advertising);
|
||||
if (iface == PHY_INTERFACE_MODE_NA) {
|
||||
netdev_err(pl->netdev,
|
||||
@@ -1669,7 +1674,7 @@ static int phylink_sfp_module_insert(voi
|
||||
}
|
||||
|
||||
config.interface = iface;
|
||||
- ret = phylink_validate(pl, support, &config);
|
||||
+ ret = phylink_validate(pl, support1, &config);
|
||||
if (ret) {
|
||||
netdev_err(pl->netdev, "validation of %s/%s with support %*pb failed: %d\n",
|
||||
phylink_an_mode_str(MLO_AN_INBAND),
|
@ -0,0 +1,94 @@
|
||||
From 254236a22109efa84c9e9f5a9c76a1719439e309 Mon Sep 17 00:00:00 2001
|
||||
From: Robert Hancock <hancock@sedsystems.ca>
|
||||
Date: Fri, 7 Jun 2019 10:42:35 -0600
|
||||
Subject: [PATCH 612/660] net: sfp: Stop SFP polling and interrupt handling
|
||||
during shutdown
|
||||
|
||||
SFP device polling can cause problems during the shutdown process if the
|
||||
parent devices of the network controller have been shut down already.
|
||||
This problem was seen on the iMX6 platform with PCIe devices, where
|
||||
accessing the device after the bus is shut down causes a hang.
|
||||
|
||||
Free any acquired GPIO interrupts and stop all delayed work in the SFP
|
||||
driver during the shutdown process, so that we ensure that no pending
|
||||
operations are still occurring after the SFP shutdown completes.
|
||||
|
||||
Signed-off-by: Robert Hancock <hancock@sedsystems.ca>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/sfp.c | 31 ++++++++++++++++++++++++++-----
|
||||
1 file changed, 26 insertions(+), 5 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/sfp.c
|
||||
+++ b/drivers/net/phy/sfp.c
|
||||
@@ -183,6 +183,7 @@ struct sfp {
|
||||
int (*write)(struct sfp *, bool, u8, void *, size_t);
|
||||
|
||||
struct gpio_desc *gpio[GPIO_MAX];
|
||||
+ int gpio_irq[GPIO_MAX];
|
||||
|
||||
bool attached;
|
||||
struct mutex st_mutex; /* Protects state */
|
||||
@@ -1803,7 +1804,7 @@ static int sfp_probe(struct platform_dev
|
||||
const struct sff_data *sff;
|
||||
struct sfp *sfp;
|
||||
bool poll = false;
|
||||
- int irq, err, i;
|
||||
+ int err, i;
|
||||
|
||||
sfp = sfp_alloc(&pdev->dev);
|
||||
if (IS_ERR(sfp))
|
||||
@@ -1885,19 +1886,22 @@ static int sfp_probe(struct platform_dev
|
||||
if (gpio_flags[i] != GPIOD_IN || !sfp->gpio[i])
|
||||
continue;
|
||||
|
||||
- irq = gpiod_to_irq(sfp->gpio[i]);
|
||||
- if (!irq) {
|
||||
+ sfp->gpio_irq[i] = gpiod_to_irq(sfp->gpio[i]);
|
||||
+ if (!sfp->gpio_irq[i]) {
|
||||
poll = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
- err = devm_request_threaded_irq(sfp->dev, irq, NULL, sfp_irq,
|
||||
+ err = devm_request_threaded_irq(sfp->dev, sfp->gpio_irq[i],
|
||||
+ NULL, sfp_irq,
|
||||
IRQF_ONESHOT |
|
||||
IRQF_TRIGGER_RISING |
|
||||
IRQF_TRIGGER_FALLING,
|
||||
dev_name(sfp->dev), sfp);
|
||||
- if (err)
|
||||
+ if (err) {
|
||||
+ sfp->gpio_irq[i] = 0;
|
||||
poll = true;
|
||||
+ }
|
||||
}
|
||||
|
||||
if (poll)
|
||||
@@ -1928,9 +1932,26 @@ static int sfp_remove(struct platform_de
|
||||
return 0;
|
||||
}
|
||||
|
||||
+static void sfp_shutdown(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct sfp *sfp = platform_get_drvdata(pdev);
|
||||
+ int i;
|
||||
+
|
||||
+ for (i = 0; i < GPIO_MAX; i++) {
|
||||
+ if (!sfp->gpio_irq[i])
|
||||
+ continue;
|
||||
+
|
||||
+ devm_free_irq(sfp->dev, sfp->gpio_irq[i], sfp);
|
||||
+ }
|
||||
+
|
||||
+ cancel_delayed_work_sync(&sfp->poll);
|
||||
+ cancel_delayed_work_sync(&sfp->timeout);
|
||||
+}
|
||||
+
|
||||
static struct platform_driver sfp_driver = {
|
||||
.probe = sfp_probe,
|
||||
.remove = sfp_remove,
|
||||
+ .shutdown = sfp_shutdown,
|
||||
.driver = {
|
||||
.name = "sfp",
|
||||
.of_match_table = sfp_of_match,
|
@ -0,0 +1,141 @@
|
||||
From b8803113537a1c1f457eba6270d46e3af305031f Mon Sep 17 00:00:00 2001
|
||||
From: Arseny Solokha <asolokha@kb.kras.ru>
|
||||
Date: Wed, 24 Jul 2019 20:31:39 +0700
|
||||
Subject: [PATCH 613/660] net: phylink: don't start and stop SGMII PHYs in SFP
|
||||
modules twice
|
||||
|
||||
SFP modules connected using the SGMII interface have their own PHYs which
|
||||
are handled by the struct phylink's phydev field. On the other hand, for
|
||||
the modules connected using 1000Base-X interface that field is not set.
|
||||
|
||||
Since commit ce0aa27ff3f6 ("sfp: add sfp-bus to bridge between network
|
||||
devices and sfp cages") phylink_start() ends up setting the phydev field
|
||||
using the sfp-bus infrastructure, which eventually calls phy_start() on it,
|
||||
and then calling phy_start() again on the same phydev from phylink_start()
|
||||
itself. Similar call sequence holds for phylink_stop(), only in the reverse
|
||||
order. This results in WARNs during network interface bringup and shutdown
|
||||
when a copper SFP module is connected, as phy_start() and phy_stop() are
|
||||
called twice in a row for the same phy_device:
|
||||
|
||||
% ip link set up dev eth0
|
||||
------------[ cut here ]------------
|
||||
called from state UP
|
||||
WARNING: CPU: 1 PID: 155 at drivers/net/phy/phy.c:895 phy_start+0x74/0xc0
|
||||
Modules linked in:
|
||||
CPU: 1 PID: 155 Comm: backend Not tainted 5.2.0+ #1
|
||||
NIP: c0227bf0 LR: c0227bf0 CTR: c004d224
|
||||
REGS: df547720 TRAP: 0700 Not tainted (5.2.0+)
|
||||
MSR: 00029000 <CE,EE,ME> CR: 24002822 XER: 00000000
|
||||
|
||||
GPR00: c0227bf0 df5477d8 df5d7080 00000014 df9d2370 df9d5ac4 1f4eb000 00000001
|
||||
GPR08: c061fe58 00000000 00000000 df5477d8 0000003c 100c8768 00000000 00000000
|
||||
GPR16: df486a00 c046f1c8 c046eea0 00000000 c046e904 c0239604 db68449c 00000000
|
||||
GPR24: e9083204 00000000 00000001 db684460 e9083404 00000000 db6dce00 db6dcc00
|
||||
NIP [c0227bf0] phy_start+0x74/0xc0
|
||||
LR [c0227bf0] phy_start+0x74/0xc0
|
||||
Call Trace:
|
||||
[df5477d8] [c0227bf0] phy_start+0x74/0xc0 (unreliable)
|
||||
[df5477e8] [c023cad0] startup_gfar+0x398/0x3f4
|
||||
[df547828] [c023cf08] gfar_enet_open+0x364/0x374
|
||||
[df547898] [c029d870] __dev_open+0xe4/0x140
|
||||
[df5478c8] [c029db70] __dev_change_flags+0xf0/0x188
|
||||
[df5478f8] [c029dc28] dev_change_flags+0x20/0x54
|
||||
[df547918] [c02ae304] do_setlink+0x310/0x818
|
||||
[df547a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
|
||||
[df547c28] [c02b222c] rtnl_newlink+0x48/0x68
|
||||
[df547c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
|
||||
[df547c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
|
||||
[df547cd8] [c02cba3c] netlink_unicast+0x114/0x19c
|
||||
[df547d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
|
||||
[df547d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
|
||||
[df547d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
|
||||
[df547e98] [c027df7c] __sys_sendmsg+0x68/0x84
|
||||
[df547ef8] [c027e430] sys_socketcall+0x1a0/0x204
|
||||
[df547f38] [c000d1d8] ret_from_syscall+0x0/0x38
|
||||
--- interrupt: c01 at 0xfd4e030
|
||||
LR = 0xfd4e010
|
||||
Instruction dump:
|
||||
813f0188 38800000 2b890005 419d0014 3d40c046 5529103a 394aa208 7c8a482e
|
||||
3c60c046 3863a1b8 4cc63182 4be009a1 <0fe00000> 48000030 3c60c046 3863a1d0
|
||||
---[ end trace d4c095aeaf6ea998 ]---
|
||||
|
||||
and
|
||||
|
||||
% ip link set down dev eth0
|
||||
------------[ cut here ]------------
|
||||
called from state HALTED
|
||||
WARNING: CPU: 1 PID: 184 at drivers/net/phy/phy.c:858 phy_stop+0x3c/0x88
|
||||
|
||||
<...>
|
||||
|
||||
Call Trace:
|
||||
[df581788] [c0228450] phy_stop+0x3c/0x88 (unreliable)
|
||||
[df581798] [c022d548] sfp_sm_phy_detach+0x1c/0x44
|
||||
[df5817a8] [c022e8cc] sfp_sm_event+0x4b0/0x87c
|
||||
[df581848] [c022f04c] sfp_upstream_stop+0x34/0x44
|
||||
[df581858] [c0225608] phylink_stop+0x7c/0xe4
|
||||
[df581868] [c023c57c] stop_gfar+0x7c/0x94
|
||||
[df581888] [c023c5b8] gfar_close+0x24/0x94
|
||||
[df5818a8] [c0298688] __dev_close_many+0xdc/0xf8
|
||||
[df5818c8] [c029db58] __dev_change_flags+0xd8/0x188
|
||||
[df5818f8] [c029dc28] dev_change_flags+0x20/0x54
|
||||
[df581918] [c02ae304] do_setlink+0x310/0x818
|
||||
[df581a08] [c02b1eb8] __rtnl_newlink+0x384/0x6b0
|
||||
[df581c28] [c02b222c] rtnl_newlink+0x48/0x68
|
||||
[df581c48] [c02ad7c8] rtnetlink_rcv_msg+0x240/0x27c
|
||||
[df581c98] [c02cc068] netlink_rcv_skb+0x8c/0xf0
|
||||
[df581cd8] [c02cba3c] netlink_unicast+0x114/0x19c
|
||||
[df581d08] [c02cbd74] netlink_sendmsg+0x2b0/0x2c0
|
||||
[df581d58] [c027b668] sock_sendmsg_nosec+0x20/0x40
|
||||
[df581d68] [c027d080] ___sys_sendmsg+0x17c/0x1dc
|
||||
[df581e98] [c027df7c] __sys_sendmsg+0x68/0x84
|
||||
[df581ef8] [c027e430] sys_socketcall+0x1a0/0x204
|
||||
[df581f38] [c000d1d8] ret_from_syscall+0x0/0x38
|
||||
|
||||
<...>
|
||||
|
||||
---[ end trace d4c095aeaf6ea999 ]---
|
||||
|
||||
SFP modules with the 1000Base-X interface are not affected.
|
||||
|
||||
Place explicit calls to phy_start() and phy_stop() before enabling or after
|
||||
disabling an attached SFP module, where phydev is not yet set (or is
|
||||
already unset), so they will be made only from the inside of sfp-bus, if
|
||||
needed.
|
||||
|
||||
Fixes: 217962615662 ("net: phy: warn if phy_start is called from invalid state")
|
||||
Signed-off-by: Arseny Solokha <asolokha@kb.kras.ru>
|
||||
Acked-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 8 ++++----
|
||||
1 file changed, 4 insertions(+), 4 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -973,10 +973,10 @@ void phylink_start(struct phylink *pl)
|
||||
}
|
||||
if (pl->link_an_mode == MLO_AN_FIXED && pl->get_fixed_state)
|
||||
mod_timer(&pl->link_poll, jiffies + HZ);
|
||||
- if (pl->sfp_bus)
|
||||
- sfp_upstream_start(pl->sfp_bus);
|
||||
if (pl->phydev)
|
||||
phy_start(pl->phydev);
|
||||
+ if (pl->sfp_bus)
|
||||
+ sfp_upstream_start(pl->sfp_bus);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(phylink_start);
|
||||
|
||||
@@ -993,10 +993,10 @@ void phylink_stop(struct phylink *pl)
|
||||
{
|
||||
ASSERT_RTNL();
|
||||
|
||||
- if (pl->phydev)
|
||||
- phy_stop(pl->phydev);
|
||||
if (pl->sfp_bus)
|
||||
sfp_upstream_stop(pl->sfp_bus);
|
||||
+ if (pl->phydev)
|
||||
+ phy_stop(pl->phydev);
|
||||
del_timer_sync(&pl->link_poll);
|
||||
if (pl->link_irq) {
|
||||
free_irq(pl->link_irq, pl);
|
@ -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
|
||||
@@ -538,26 +538,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;
|
||||
-
|
||||
- netdev_err(pl->netdev, "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);
|
||||
+ netdev_err(pl->netdev, "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
|
||||
@@ -3,6 +3,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>
|
||||
|
||||
@@ -444,45 +445,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
|
||||
@@ -541,7 +541,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);
|
||||
netdev_err(pl->netdev, "unable to attach SFP bus: %d\n", ret);
|
||||
@@ -550,7 +550,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -634,8 +637,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
|
||||
@@ -328,10 +328,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)
|
||||
{
|
||||
@@ -347,11 +356,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;
|
||||
}
|
||||
|
||||
@@ -445,13 +454,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,
|
||||
@@ -461,9 +469,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;
|
||||
@@ -481,7 +487,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;
|
||||
|
||||
@@ -494,33 +532,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
|
||||
@@ -330,7 +330,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
|
||||
@@ -1479,19 +1479,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) {
|
||||
@@ -1531,27 +1546,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 ||
|
||||
@@ -1562,7 +1560,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;
|
||||
}
|
||||
|
||||
@@ -1617,6 +1614,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
|
||||
@@ -1489,15 +1489,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;
|
||||
}
|
||||
}
|
||||
@@ -1559,6 +1552,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
|
||||
@@ -1180,7 +1180,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;
|
||||
@@ -1504,22 +1504,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);
|
||||
}
|
||||
@@ -1527,7 +1527,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 */
|
||||
@@ -1535,7 +1535,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
|
||||
@@ -1500,6 +1500,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) {
|
||||
@@ -1509,9 +1517,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)
|
||||
@@ -1533,10 +1539,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
|
||||
@@ -147,11 +147,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)
|
||||
|
||||
@@ -1495,8 +1494,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)
|
||||
{
|
||||
@@ -1512,7 +1511,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
|
||||
@@ -196,6 +196,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;
|
||||
@@ -1309,17 +1311,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)) !=
|
||||
@@ -1328,23 +1327,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));
|
||||
@@ -1364,7 +1373,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:
|
||||
@@ -1451,6 +1461,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;
|
||||
@@ -1474,6 +1489,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
|
||||
@@ -1320,25 +1320,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
|
||||
@@ -1492,11 +1492,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;
|
||||
|
||||
@@ -1534,10 +1529,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
|
||||
@@ -1288,14 +1288,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.
|
||||
@@ -1580,8 +1576,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
|
||||
@@ -52,6 +52,7 @@ enum {
|
||||
SFP_DEV_UP,
|
||||
|
||||
SFP_S_DOWN = 0,
|
||||
+ SFP_S_WAIT,
|
||||
SFP_S_INIT,
|
||||
SFP_S_WAIT_LOS,
|
||||
SFP_S_LINK_UP,
|
||||
@@ -108,6 +109,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",
|
||||
@@ -139,6 +141,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)
|
||||
@@ -159,9 +162,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);
|
||||
@@ -1202,8 +1202,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");
|
||||
@@ -1558,6 +1556,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 ||
|
||||
@@ -1575,17 +1575,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;
|
||||
|
||||
@@ -1593,7 +1621,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
|
||||
@@ -1269,7 +1269,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,
|
||||
@@ -1279,7 +1279,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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1619,14 +1619,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;
|
||||
@@ -1634,7 +1634,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);
|
||||
@@ -1650,7 +1650,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
|
||||
@@ -54,6 +54,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,
|
||||
@@ -111,6 +112,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",
|
||||
@@ -1595,8 +1597,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
|
||||
@@ -1618,10 +1618,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
|
||||
@@ -34,6 +34,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,
|
||||
@@ -48,7 +50,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,
|
||||
@@ -78,6 +81,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",
|
||||
};
|
||||
@@ -92,6 +96,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",
|
||||
@@ -186,7 +192,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;
|
||||
@@ -1494,17 +1499,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;
|
||||
}
|
||||
@@ -1515,17 +1529,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;
|
||||
|
||||
@@ -1691,8 +1708,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",
|
||||
@@ -1705,15 +1722,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
|
||||
@@ -47,6 +47,7 @@ enum {
|
||||
SFP_MOD_EMPTY = 0,
|
||||
SFP_MOD_PROBE,
|
||||
SFP_MOD_HPOWER,
|
||||
+ SFP_MOD_WAITPWR,
|
||||
SFP_MOD_PRESENT,
|
||||
SFP_MOD_ERROR,
|
||||
|
||||
@@ -69,6 +70,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",
|
||||
};
|
||||
@@ -1358,37 +1360,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)
|
||||
@@ -1484,7 +1483,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)
|
||||
@@ -1529,13 +1528,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;
|
||||
}
|
||||
@@ -1547,26 +1555,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
|
||||
@@ -45,11 +45,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,
|
||||
@@ -68,11 +69,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)
|
||||
@@ -1479,16 +1481,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);
|
||||
|
||||
@@ -1539,12 +1538,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;
|
||||
}
|
||||
|
||||
@@ -1555,6 +1554,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;
|
||||
|
||||
@@ -1568,6 +1568,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;
|
||||
@@ -1577,12 +1591,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:
|
||||
@@ -1750,8 +1769,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)
|
||||
@@ -2001,6 +2018,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
|
||||
@@ -165,9 +165,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).
|
||||
@@ -202,6 +205,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;
|
||||
@@ -1392,7 +1397,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;
|
||||
@@ -1402,7 +1407,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;
|
||||
}
|
||||
|
||||
@@ -1549,8 +1555,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:
|
||||
@@ -1558,10 +1567,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);
|
||||
@@ -1596,7 +1614,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
|
||||
@@ -216,6 +216,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
|
||||
@@ -1094,29 +1096,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]))
|
||||
@@ -1126,18 +1126,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)
|
||||
{
|
||||
@@ -1147,6 +1181,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 */
|
||||
@@ -1483,10 +1526,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;
|
||||
}
|
||||
|
||||
@@ -1635,6 +1674,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)
|
||||
@@ -1936,6 +1984,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;
|
||||
}
|
||||
|
||||
@@ -1943,6 +1993,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
|
||||
@@ -30,6 +30,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>
|
||||
@@ -871,6 +872,9 @@ void phy_stop(struct phy_device *phydev)
|
||||
if (phy_interrupt_is_valid(phydev))
|
||||
phy_disable_interrupts(phydev);
|
||||
|
||||
+ if (phydev->sfp_bus)
|
||||
+ sfp_upstream_stop(phydev->sfp_bus);
|
||||
+
|
||||
phydev->state = PHY_HALTED;
|
||||
|
||||
out_unlock:
|
||||
@@ -899,6 +903,9 @@ void phy_start(struct phy_device *phydev
|
||||
|
||||
mutex_lock(&phydev->lock);
|
||||
|
||||
+ if (phydev->sfp_bus)
|
||||
+ sfp_upstream_start(phydev->sfp_bus);
|
||||
+
|
||||
switch (phydev->state) {
|
||||
case PHY_STARTING:
|
||||
phydev->state = PHY_PENDING;
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <linux/ethtool.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>
|
||||
@@ -944,6 +945,65 @@ void phy_attached_print(struct phy_devic
|
||||
EXPORT_SYMBOL(phy_attached_print);
|
||||
|
||||
/**
|
||||
+ * 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
|
||||
@@ -1016,6 +1076,9 @@ int phy_attach_direct(struct net_device
|
||||
phydev->attached_dev = dev;
|
||||
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
|
||||
@@ -1950,6 +2013,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
|
||||
@@ -184,6 +184,8 @@ static inline const char *phy_modes(phy_
|
||||
|
||||
struct device;
|
||||
struct phylink;
|
||||
+struct sfp_bus;
|
||||
+struct sfp_upstream_ops;
|
||||
struct sk_buff;
|
||||
|
||||
/*
|
||||
@@ -382,6 +384,8 @@ struct phy_c45_device_ids {
|
||||
* irq: IRQ number of the PHY's interrupt (-1 if none)
|
||||
* phy_timer: The timer for handling the state machine
|
||||
* phy_queue: A work_queue for the phy_mac_interrupt
|
||||
+ * 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.
|
||||
@@ -471,6 +475,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;
|
||||
|
||||
@@ -1031,6 +1038,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
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <linux/hwmon.h>
|
||||
#include <linux/marvell_phy.h>
|
||||
#include <linux/phy.h>
|
||||
+#include <linux/sfp.h>
|
||||
|
||||
enum {
|
||||
MV_PMA_BOOT = 0xc050,
|
||||
@@ -219,6 +220,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;
|
||||
@@ -249,7 +272,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,45 @@
|
||||
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
|
||||
@@ -678,12 +678,6 @@ static int phylink_bringup_phy(struct ph
|
||||
u32 advertising;
|
||||
int ret;
|
||||
|
||||
- memset(&config, 0, sizeof(config));
|
||||
- ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
- ethtool_convert_legacy_u32_to_link_mode(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:
|
||||
@@ -691,10 +685,13 @@ 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));
|
||||
+ ethtool_convert_legacy_u32_to_link_mode(supported, phy->supported);
|
||||
+ ethtool_convert_legacy_u32_to_link_mode(config.advertising,
|
||||
+ phy->advertising);
|
||||
+ config.interface = pl->link_config.interface;
|
||||
|
||||
ret = phylink_validate(pl, supported, &config);
|
||||
if (ret)
|
@ -0,0 +1,63 @@
|
||||
From 1be8018db381200c24854e0c299206c557f76fe0 Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Mon, 11 Nov 2019 11:58:09 +0000
|
||||
Subject: [PATCH 638/660] net: phy: avoid matching all-ones clause 45 PHY IDs
|
||||
|
||||
We currently match clause 45 PHYs using any ID read from a MMD marked
|
||||
as present in the "Devices in package" registers 5 and 6. However,
|
||||
this is incorrect. 45.2 says:
|
||||
|
||||
"The definition of the term package is vendor specific and could be
|
||||
a chip, module, or other similar entity."
|
||||
|
||||
so a package could be more or less than the whole PHY - a PHY could be
|
||||
made up of several modules instantiated onto a single chip such as the
|
||||
Marvell 88x3310, or some of the MMDs could be disabled according to
|
||||
chip configuration, such as the Broadcom 84881.
|
||||
|
||||
In the case of Broadcom 84881, the "Devices in package" registers
|
||||
contain 0xc000009b, meaning that there is a PHYXS present in the
|
||||
package, but all registers in MMD 4 return 0xffff. This leads to our
|
||||
matching code incorrectly binding this PHY to one of our generic PHY
|
||||
drivers.
|
||||
|
||||
This patch changes the way we determine whether to attempt to match a
|
||||
MMD identifier, or use it to request a module - if the identifier is
|
||||
all-ones, then we skip over it. When reading the identifiers, we
|
||||
initialise phydev->c45_ids.device_ids to all-ones, only reading the
|
||||
device ID if the "Devices in package" registers indicates we should.
|
||||
|
||||
This avoids the generic drivers incorrectly matching on a PHY ID of
|
||||
0xffffffff.
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phy_device.c | 7 +++++--
|
||||
1 file changed, 5 insertions(+), 2 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phy_device.c
|
||||
+++ b/drivers/net/phy/phy_device.c
|
||||
@@ -335,7 +335,7 @@ static int phy_bus_match(struct device *
|
||||
|
||||
if (phydev->is_c45) {
|
||||
for (i = 1; i < num_ids; i++) {
|
||||
- if (!(phydev->c45_ids.devices_in_package & (1 << i)))
|
||||
+ if (phydev->c45_ids.device_ids[i] == 0xffffffff)
|
||||
continue;
|
||||
|
||||
if ((phydrv->phy_id & phydrv->phy_id_mask) ==
|
||||
@@ -623,10 +623,13 @@ static int get_phy_id(struct mii_bus *bu
|
||||
*/
|
||||
struct phy_device *get_phy_device(struct mii_bus *bus, int addr, bool is_c45)
|
||||
{
|
||||
- struct phy_c45_device_ids c45_ids = {0};
|
||||
+ struct phy_c45_device_ids c45_ids;
|
||||
u32 phy_id = 0;
|
||||
int r;
|
||||
|
||||
+ c45_ids.devices_in_package = 0;
|
||||
+ memset(c45_ids.device_ids, 0xff, sizeof(c45_ids.device_ids));
|
||||
+
|
||||
r = get_phy_id(bus, addr, &phy_id, is_c45, &c45_ids);
|
||||
if (r)
|
||||
return ERR_PTR(r);
|
@ -0,0 +1,66 @@
|
||||
From 4c9633f75dc35abe1b9261e0415d77802f35741d Mon Sep 17 00:00:00 2001
|
||||
From: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
Date: Tue, 5 Nov 2019 11:58:00 +0000
|
||||
Subject: [PATCH 639/660] net: phylink: fix link mode modification in PHY mode
|
||||
|
||||
Modifying the link settings via phylink_ethtool_ksettings_set() and
|
||||
phylink_ethtool_set_pauseparam() didn't always work as intended for
|
||||
PHY based setups, as calling phylink_mac_config() would result in the
|
||||
unresolved configuration being committed to the MAC, rather than the
|
||||
configuration with the speed and duplex setting.
|
||||
|
||||
This would work fine if the update caused the link to renegotiate,
|
||||
but if no settings have changed, phylib won't trigger a renegotiation
|
||||
cycle, and the MAC will be left incorrectly configured.
|
||||
|
||||
Avoid calling phylink_mac_config() unless we are using an inband mode
|
||||
in phylink_ethtool_ksettings_set(), and use phy_set_asym_pause() as
|
||||
introduced in 4.20 to set the PHY settings in
|
||||
phylink_ethtool_set_pauseparam().
|
||||
|
||||
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
|
||||
---
|
||||
drivers/net/phy/phylink.c | 24 ++++++++++++++++--------
|
||||
1 file changed, 16 insertions(+), 8 deletions(-)
|
||||
|
||||
--- a/drivers/net/phy/phylink.c
|
||||
+++ b/drivers/net/phy/phylink.c
|
||||
@@ -1210,7 +1210,13 @@ int phylink_ethtool_ksettings_set(struct
|
||||
pl->link_config.duplex = our_kset.base.duplex;
|
||||
pl->link_config.an_enabled = our_kset.base.autoneg != AUTONEG_DISABLE;
|
||||
|
||||
- if (!test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
|
||||
+ /* If we have a PHY, phylib will call our link state function if the
|
||||
+ * mode has changed, which will trigger a resolve and update the MAC
|
||||
+ * configuration. For a fixed link, this isn't able to change any
|
||||
+ * parameters, which just leaves inband mode.
|
||||
+ */
|
||||
+ if (pl->link_an_mode == MLO_AN_INBAND &&
|
||||
+ !test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
|
||||
phylink_mac_config(pl, &pl->link_config);
|
||||
phylink_mac_an_restart(pl);
|
||||
}
|
||||
@@ -1290,14 +1296,16 @@ int phylink_ethtool_set_pauseparam(struc
|
||||
if (pause->tx_pause)
|
||||
config->pause |= MLO_PAUSE_TX;
|
||||
|
||||
- if (!test_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state)) {
|
||||
+ /* If we have a PHY, phylib will call our link state function if the
|
||||
+ * mode has changed, which will trigger a resolve and update the MAC
|
||||
+ * configuration.
|
||||
+ */
|
||||
+ if (pl->phydev) {
|
||||
+ phy_set_asym_pause(pl->phydev, pause->rx_pause,
|
||||
+ pause->tx_pause);
|
||||
+ } else if (!test_bit(PHYLINK_DISABLE_STOPPED,
|
||||
+ &pl->phylink_disable_state)) {
|
||||
switch (pl->link_an_mode) {
|
||||
- case MLO_AN_PHY:
|
||||
- /* Silently mark the carrier down, and then trigger a resolve */
|
||||
- netif_carrier_off(pl->netdev);
|
||||
- phylink_run_resolve(pl);
|
||||
- break;
|
||||
-
|
||||
case MLO_AN_FIXED:
|
||||
/* Should we allow fixed links to change against the config? */
|
||||
phylink_resolve_flow(pl, config);
|
@ -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
|
||||
@@ -9,6 +9,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
|
||||
*/
|
||||
@@ -21,6 +27,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;
|
||||
@@ -30,6 +37,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
|
||||
@@ -233,6 +280,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);
|
||||
@@ -609,6 +659,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);
|
||||
|
||||
@@ -622,6 +674,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
|
||||
@@ -37,7 +37,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
|
||||
@@ -199,7 +199,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;
|
||||
@@ -393,24 +396,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)
|
||||
@@ -1342,11 +1411,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
|
||||
@@ -1509,7 +1573,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);
|
||||
@@ -1699,6 +1763,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;
|
||||
}
|
||||
@@ -1710,7 +1775,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;
|
||||
@@ -1966,7 +2034,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)
|
||||
@@ -2010,7 +2081,6 @@ static int sfp_probe(struct platform_dev
|
||||
{
|
||||
const struct sff_data *sff;
|
||||
struct sfp *sfp;
|
||||
- bool poll = false;
|
||||
int err, i;
|
||||
|
||||
sfp = sfp_alloc(&pdev->dev);
|
||||
@@ -2100,7 +2170,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;
|
||||
}
|
||||
|
||||
@@ -2112,11 +2182,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),
|
6101
target/linux/generic/config-5.4
Normal file
6101
target/linux/generic/config-5.4
Normal file
File diff suppressed because it is too large
Load Diff
206
target/linux/generic/hack-5.4/204-module_strip.patch
Normal file
206
target/linux/generic/hack-5.4/204-module_strip.patch
Normal file
@ -0,0 +1,206 @@
|
||||
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
|
||||
@@ -160,6 +160,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)
|
||||
@@ -203,12 +204,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 \
|
||||
@@ -235,7 +236,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) \
|
||||
static struct module_version_attribute ___modver_attr = { \
|
||||
@@ -257,7 +260,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)
|
||||
|
||||
struct notifier_block;
|
||||
|
||||
--- a/include/linux/moduleparam.h
|
||||
+++ b/include/linux/moduleparam.h
|
||||
@@ -17,6 +17,16 @@
|
||||
/* Chosen so that structs with an unsigned long line up. */
|
||||
#define MAX_PARAM_PREFIX_LEN (64 - sizeof(unsigned long))
|
||||
|
||||
+/* This struct is here for syntactic coherency, it is not used */
|
||||
+#define __MODULE_INFO_DISABLED(name) \
|
||||
+ struct __UNIQUE_ID(name) {}
|
||||
+
|
||||
+#ifdef CONFIG_MODULE_STRIPPED
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
+#else
|
||||
+#define __MODULE_INFO_STRIP(tag, name, info) __MODULE_INFO(tag, name, info)
|
||||
+#endif
|
||||
+
|
||||
#ifdef MODULE
|
||||
#define __MODULE_INFO(tag, name, info) \
|
||||
static const char __UNIQUE_ID(name)[] \
|
||||
@@ -24,8 +34,7 @@ static const char __UNIQUE_ID(name)[]
|
||||
= __stringify(tag) "=" info
|
||||
#else /* !MODULE */
|
||||
/* This struct is here for syntactic coherency, it is not used */
|
||||
-#define __MODULE_INFO(tag, name, info) \
|
||||
- struct __UNIQUE_ID(name) {}
|
||||
+#define __MODULE_INFO(tag, name, info) __MODULE_INFO_DISABLED(name)
|
||||
#endif
|
||||
#define __MODULE_PARM_TYPE(name, _type) \
|
||||
__MODULE_INFO(parmtype, name##type, #name ":" _type)
|
||||
@@ -33,7 +42,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
|
||||
@@ -1997,6 +1997,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
|
||||
@@ -3029,9 +3029,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;
|
||||
|
||||
@@ -3052,6 +3054,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
|
||||
@@ -1983,7 +1983,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
|
||||
}
|
||||
if (!is_vmlinux(modname) || vmlinux_section_warnings)
|
||||
check_sec_ref(mod, modname, &info);
|
||||
@@ -2146,8 +2148,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, "__attribute__((section(\".gnu.linkonce.this_module\"))) = {\n");
|
||||
@@ -2164,8 +2168,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 */
|
||||
@@ -2178,8 +2184,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
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2278,11 +2286,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)
|
||||
@@ -2519,7 +2529,9 @@ int main(int argc, char **argv)
|
||||
add_staging_flag(&buf, mod->name);
|
||||
err |= add_versions(&buf, mod);
|
||||
add_depends(&buf, mod, modules);
|
||||
+#ifndef CONFIG_MODULE_STRIPPED
|
||||
add_moddevtable(&buf, mod);
|
||||
+#endif
|
||||
add_srcversion(&buf, mod);
|
||||
|
||||
sprintf(fname, "%s.mod.c", mod->name);
|
44
target/linux/generic/hack-5.4/207-disable-modorder.patch
Normal file
44
target/linux/generic/hack-5.4/207-disable-modorder.patch
Normal file
@ -0,0 +1,44 @@
|
||||
From c9ef4ab0f54356ee9f91d9676ea0ec123840ddc7 Mon Sep 17 00:00:00 2001
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 7 Jul 2017 16:57:33 +0200
|
||||
Subject: kernel: do not build modules.order
|
||||
|
||||
It is not needed for anything on the system and skipping this saves some
|
||||
build time, especially in cases where there is nothing to do.
|
||||
|
||||
lede-commit: afc1675833a7bf5df094f59f7250369520646d04
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
Makefile | 2 --
|
||||
scripts/Makefile.build | 2 +-
|
||||
2 files changed, 1 insertion(+), 3 deletions(-)
|
||||
|
||||
--- a/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -1232,7 +1232,6 @@ all: modules
|
||||
|
||||
PHONY += modules
|
||||
modules: $(vmlinux-dirs) $(if $(KBUILD_BUILTIN),vmlinux) modules.builtin
|
||||
- $(Q)$(AWK) '!x[$$0]++' $(vmlinux-dirs:%=$(objtree)/%/modules.order) > $(objtree)/modules.order
|
||||
@$(kecho) ' Building modules, stage 2.';
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modpost
|
||||
|
||||
@@ -1261,7 +1260,6 @@ _modinst_:
|
||||
rm -f $(MODLIB)/build ; \
|
||||
ln -s $(CURDIR) $(MODLIB)/build ; \
|
||||
fi
|
||||
- @cp -f $(objtree)/modules.order $(MODLIB)/
|
||||
@cp -f $(objtree)/modules.builtin $(MODLIB)/
|
||||
$(Q)$(MAKE) -f $(srctree)/scripts/Makefile.modinst
|
||||
|
||||
--- a/scripts/Makefile.build
|
||||
+++ b/scripts/Makefile.build
|
||||
@@ -78,7 +78,7 @@ modorder-target := $(obj)/modules.order
|
||||
# We keep a list of all modules in $(MODVERDIR)
|
||||
|
||||
__build: $(if $(KBUILD_BUILTIN),$(builtin-target) $(lib-target) $(extra-y)) \
|
||||
- $(if $(KBUILD_MODULES),$(obj-m) $(modorder-target)) \
|
||||
+ $(if $(KBUILD_MODULES),$(obj-m)) \
|
||||
$(subdir-ym) $(always)
|
||||
@:
|
||||
|
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,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
|
||||
@@ -113,7 +113,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)])
|
||||
|
192
target/linux/generic/hack-5.4/220-gc_sections.patch
Normal file
192
target/linux/generic/hack-5.4/220-gc_sections.patch
Normal file
@ -0,0 +1,192 @@
|
||||
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/Makefile
|
||||
+++ b/Makefile
|
||||
@@ -294,6 +294,11 @@ else
|
||||
scripts/Kbuild.include: ;
|
||||
include scripts/Kbuild.include
|
||||
|
||||
+ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
|
||||
+KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
+LDFLAGS_vmlinux += --gc-sections
|
||||
+endif
|
||||
+
|
||||
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
|
||||
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
|
||||
KERNELVERSION = $(VERSION)$(if $(PATCHLEVEL),.$(PATCHLEVEL)$(if $(SUBLEVEL),.$(SUBLEVEL)))$(EXTRAVERSION)
|
||||
@@ -782,11 +787,6 @@ ifdef CONFIG_DEBUG_SECTION_MISMATCH
|
||||
KBUILD_CFLAGS += $(call cc-option, -fno-inline-functions-called-once)
|
||||
endif
|
||||
|
||||
-ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
|
||||
-KBUILD_CFLAGS_KERNEL += -ffunction-sections -fdata-sections
|
||||
-LDFLAGS_vmlinux += --gc-sections
|
||||
-endif
|
||||
-
|
||||
# arch Makefile may override CC so keep this after arch Makefile is included
|
||||
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
|
||||
|
||||
--- a/arch/arm/Kconfig
|
||||
+++ b/arch/arm/Kconfig
|
||||
@@ -98,6 +98,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 NO_BOOTMEM
|
||||
--- 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 = .; \
|
||||
--- a/arch/mips/Kconfig
|
||||
+++ b/arch/mips/Kconfig
|
||||
@@ -43,6 +43,7 @@ config MIPS
|
||||
select HAVE_ARCH_TRANSPARENT_HUGEPAGE if CPU_SUPPORTS_HUGEPAGES && 64BIT
|
||||
select HAVE_CBPF_JIT if (!64BIT && !CPU_MICROMIPS)
|
||||
select HAVE_EBPF_JIT if (64BIT && !CPU_MICROMIPS)
|
||||
+ select HAVE_LD_DEAD_CODE_DATA_ELIMINATION
|
||||
select HAVE_CONTEXT_TRACKING
|
||||
select HAVE_COPY_THREAD_TLS
|
||||
select HAVE_C_RECORDMCOUNT
|
||||
--- a/arch/mips/kernel/vmlinux.lds.S
|
||||
+++ b/arch/mips/kernel/vmlinux.lds.S
|
||||
@@ -72,7 +72,7 @@ SECTIONS
|
||||
/* Exception table for data bus errors */
|
||||
__dbe_table : {
|
||||
__start___dbe_table = .;
|
||||
- *(__dbe_table)
|
||||
+ KEEP(*(__dbe_table))
|
||||
__stop___dbe_table = .;
|
||||
}
|
||||
|
||||
@@ -123,7 +123,7 @@ SECTIONS
|
||||
. = ALIGN(4);
|
||||
.mips.machines.init : AT(ADDR(.mips.machines.init) - LOAD_OFFSET) {
|
||||
__mips_machines_start = .;
|
||||
- *(.mips.machines.init)
|
||||
+ KEEP(*(.mips.machines.init))
|
||||
__mips_machines_end = .;
|
||||
}
|
||||
|
101
target/linux/generic/hack-5.4/221-module_exports.patch
Normal file
101
target/linux/generic/hack-5.4/221-module_exports.patch
Normal file
@ -0,0 +1,101 @@
|
||||
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)
|
||||
|
||||
@@ -372,14 +382,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 = .; \
|
||||
} \
|
||||
\
|
||||
@@ -441,7 +451,7 @@
|
||||
\
|
||||
/* Kernel symbol table: strings */ \
|
||||
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||
- *(__ksymtab_strings) \
|
||||
+ *(__ksymtab_strings+*) \
|
||||
} \
|
||||
\
|
||||
/* __*init sections */ \
|
||||
@@ -841,6 +851,8 @@
|
||||
EXIT_TEXT \
|
||||
EXIT_DATA \
|
||||
EXIT_CALL \
|
||||
+ SYMTAB_DISCARD \
|
||||
+ SYMTAB_DISCARD_GPL \
|
||||
*(.discard) \
|
||||
*(.discard.*) \
|
||||
}
|
||||
--- a/include/linux/export.h
|
||||
+++ b/include/linux/export.h
|
||||
@@ -74,12 +74,19 @@ struct kernel_symbol {
|
||||
};
|
||||
#endif
|
||||
|
||||
+#ifdef MODULE
|
||||
+#define __EXPORT_SUFFIX(sym)
|
||||
+#else
|
||||
+#define __EXPORT_SUFFIX(sym) "+" #sym
|
||||
+#endif
|
||||
+
|
||||
/* For every exported symbol, place a struct in the __ksymtab section */
|
||||
#define ___EXPORT_SYMBOL(sym, sec) \
|
||||
extern typeof(sym) sym; \
|
||||
__CRC_SYMBOL(sym, sec) \
|
||||
static const char __kstrtab_##sym[] \
|
||||
- __attribute__((section("__ksymtab_strings"), used, aligned(1))) \
|
||||
+ __attribute__((section("__ksymtab_strings" \
|
||||
+ __EXPORT_SUFFIX(sym)), used, aligned(1))) \
|
||||
= #sym; \
|
||||
__KSYMTAB_ENTRY(sym, sec)
|
||||
|
||||
--- a/scripts/Makefile.build
|
||||
+++ b/scripts/Makefile.build
|
||||
@@ -408,7 +408,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
|
||||
@@ -325,7 +325,7 @@ cmd_bzip2 = (cat $(filter-out FORCE,$^)
|
||||
|
||||
quiet_cmd_lzma = LZMA $@
|
||||
cmd_lzma = (cat $(filter-out FORCE,$^) | \
|
||||
- lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
+ lzma e -d20 -lc1 -lp2 -pb2 -eos -si -so && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||
(rm -f $@ ; false)
|
||||
|
||||
quiet_cmd_lzo = LZO $@
|
||||
--- a/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
|
||||
@@ -241,7 +241,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
|
||||
@@ -1077,7 +1076,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
|
197
target/linux/generic/hack-5.4/251-sound_kconfig.patch
Normal file
197
target/linux/generic/hack-5.4/251-sound_kconfig.patch
Normal file
@ -0,0 +1,197 @@
|
||||
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
|
||||
|
||||
@@ -64,7 +64,7 @@ config CRYPTO_BLKCIPHER2
|
||||
select CRYPTO_WORKQUEUE
|
||||
|
||||
config CRYPTO_HASH
|
||||
- tristate
|
||||
+ tristate "HASH"
|
||||
select CRYPTO_HASH2
|
||||
select CRYPTO_ALGAPI
|
||||
|
||||
@@ -73,7 +73,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
|
||||
@@ -28,6 +28,7 @@ config SSB_SPROM
|
||||
config SSB_BLOCKIO
|
||||
bool
|
||||
depends on SSB
|
||||
+ default y
|
||||
|
||||
config SSB_PCIHOST_POSSIBLE
|
||||
bool
|
||||
@@ -48,7 +49,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
|
||||
@@ -377,16 +377,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
|
||||
@@ -10,7 +10,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,5 +1,5 @@
|
||||
config WIRELESS_EXT
|
||||
- bool
|
||||
+ bool "Wireless extensions"
|
||||
|
||||
config WEXT_CORE
|
||||
def_bool y
|
||||
@@ -11,10 +11,10 @@ config WEXT_PROC
|
||||
depends on WEXT_CORE
|
||||
|
||||
config WEXT_SPY
|
||||
- bool
|
||||
+ bool "WEXT_SPY"
|
||||
|
||||
config WEXT_PRIV
|
||||
- bool
|
||||
+ bool "WEXT_PRIV"
|
||||
|
||||
config CFG80211
|
||||
tristate "cfg80211 - wireless configuration API"
|
||||
@@ -202,7 +202,7 @@ config CFG80211_WEXT_EXPORT
|
||||
endif # CFG80211
|
||||
|
||||
config LIB80211
|
||||
- tristate
|
||||
+ tristate "LIB80211"
|
||||
default n
|
||||
help
|
||||
This options enables a library of common routines used
|
||||
@@ -211,13 +211,16 @@ config LIB80211
|
||||
Drivers should select this themselves if needed.
|
||||
|
||||
config LIB80211_CRYPT_WEP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_WEP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_CRYPT_CCMP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_CCMP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_CRYPT_TKIP
|
||||
- tristate
|
||||
+ tristate "LIB80211_CRYPT_TKIP"
|
||||
+ select LIB80211
|
||||
|
||||
config LIB80211_DEBUG
|
||||
bool "lib80211 debugging messages"
|
||||
--- a/sound/core/Kconfig
|
||||
+++ b/sound/core/Kconfig
|
||||
@@ -16,7 +16,7 @@ config SND_DMAENGINE_PCM
|
||||
tristate
|
||||
|
||||
config SND_HWDEP
|
||||
- tristate
|
||||
+ tristate "Sound hardware support"
|
||||
|
||||
config SND_SEQ_DEVICE
|
||||
tristate
|
||||
@@ -26,7 +26,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
|
110
target/linux/generic/hack-5.4/259-regmap_dynamic.patch
Normal file
110
target/linux/generic/hack-5.4/259-regmap_dynamic.patch
Normal file
@ -0,0 +1,110 @@
|
||||
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)
|
||||
select IRQ_DOMAIN if REGMAP_IRQ
|
||||
- bool
|
||||
+ tristate
|
||||
|
||||
config REGCACHE_COMPRESSED
|
||||
select LZO_COMPRESS
|
||||
@@ -18,6 +17,7 @@ config REGMAP_AC97
|
||||
|
||||
config REGMAP_I2C
|
||||
tristate
|
||||
+ select REGMAP
|
||||
depends on I2C
|
||||
|
||||
config REGMAP_SLIMBUS
|
||||
@@ -26,20 +26,26 @@ config REGMAP_SLIMBUS
|
||||
|
||||
config REGMAP_SPI
|
||||
tristate
|
||||
+ select REGMAP
|
||||
+ depends on SPI_MASTER
|
||||
depends on SPI
|
||||
|
||||
config REGMAP_SPMI
|
||||
+ select REGMAP
|
||||
tristate
|
||||
depends on SPMI
|
||||
|
||||
config REGMAP_W1
|
||||
+ select REGMAP
|
||||
tristate
|
||||
depends on W1
|
||||
|
||||
config REGMAP_MMIO
|
||||
tristate
|
||||
+ select REGMAP
|
||||
|
||||
config REGMAP_IRQ
|
||||
+ select REGMAP
|
||||
bool
|
||||
|
||||
config REGMAP_SOUNDWIRE
|
||||
--- 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
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
+#include <linux/module.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/of.h>
|
||||
@@ -3039,3 +3040,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
|
||||
@@ -187,7 +187,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,60 @@
|
||||
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
|
||||
@@ -144,13 +144,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"
|
||||
@@ -163,7 +163,6 @@ config CRYPTO_USER
|
||||
config CRYPTO_MANAGER_DISABLE_TESTS
|
||||
bool "Disable run-time self tests"
|
||||
default y
|
||||
- depends on CRYPTO_MANAGER2
|
||||
help
|
||||
Disable run-time self tests that normally take place at
|
||||
algorithm registration.
|
||||
--- a/crypto/algboss.c
|
||||
+++ b/crypto/algboss.c
|
||||
@@ -247,8 +247,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;
|
||||
|
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
|
||||
@@ -1,7 +1,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
|
||||
@@ -13,19 +17,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
|
||||
@@ -4,5 +4,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,33 @@
|
||||
From 2579d9b982c7232f9354bcca5262e26a84c38799 Mon Sep 17 00:00:00 2001
|
||||
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
Date: Fri, 2 Nov 2018 17:40:32 +0100
|
||||
Subject: [PATCH] nvmem: make CONFIG_NVMEM tristate again
|
||||
|
||||
Only build it in when OF_NET is selected and make it possible to build
|
||||
it as module otherwise.
|
||||
|
||||
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||
---
|
||||
drivers/nvmem/Kconfig | 2 +-
|
||||
drivers/of/Kconfig | 1 +
|
||||
2 files changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
--- a/drivers/nvmem/Kconfig
|
||||
+++ b/drivers/nvmem/Kconfig
|
||||
@@ -1,5 +1,5 @@
|
||||
menuconfig NVMEM
|
||||
- bool "NVMEM Support"
|
||||
+ tristate "NVMEM Support"
|
||||
help
|
||||
Support for NVMEM(Non Volatile Memory) devices like EEPROM, EFUSES...
|
||||
|
||||
--- a/drivers/of/Kconfig
|
||||
+++ b/drivers/of/Kconfig
|
||||
@@ -71,6 +71,7 @@ config OF_IRQ
|
||||
|
||||
config OF_NET
|
||||
depends on NETDEVICES
|
||||
+ select NVMEM
|
||||
def_bool y
|
||||
|
||||
config OF_MDIO
|
@ -0,0 +1,66 @@
|
||||
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
|
||||
@@ -683,16 +683,48 @@ 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; \
|
||||
\
|
||||
__##pfx##flush_prologue \
|
||||
\
|
||||
- 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; \
|
||||
} \
|
||||
\
|
||||
__##pfx##flush_epilogue \
|
@ -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
|
||||
@@ -1144,6 +1144,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
|
||||
|
||||
+#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
|
||||
@@ -60,20 +60,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_LDFLAGS_MODULE += -T $(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
|
||||
@@ -460,7 +460,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;
|
||||
}
|
||||
|
||||
@@ -1904,7 +1904,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
|
||||
@@ -426,11 +426,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;
|
||||
}
|
||||
@@ -863,6 +864,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
|
||||
@@ -870,22 +886,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
|
||||
@@ -108,10 +108,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
|
||||
@@ -337,6 +337,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
|
||||
@@ -170,6 +170,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)
|
||||
{
|
||||
@@ -810,6 +834,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 = BIT(0),
|
||||
+ XT_CONNMARK_DSCP = BIT(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
|
||||
@@ -36,12 +36,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)
|
||||
@@ -49,12 +50,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);
|
||||
@@ -93,20 +106,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);
|
||||
}
|
||||
@@ -177,6 +206,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
|
||||
@@ -163,6 +163,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
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <net/netfilter/nf_conntrack.h>
|
||||
#include <net/netfilter/nf_conntrack_core.h>
|
||||
#include <net/netfilter/nf_conntrack_tuple.h>
|
||||
+#include <net/netfilter/nf_conntrack_acct.h>
|
||||
|
||||
struct flow_offload_entry {
|
||||
struct flow_offload flow;
|
||||
@@ -149,6 +150,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
|
||||
@@ -11,6 +11,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>
|
||||
@@ -267,6 +268,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;
|
||||
@@ -487,6 +489,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,553 @@
|
||||
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
|
||||
@@ -63,8 +63,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
|
||||
@@ -73,6 +71,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
|
||||
@@ -80,7 +80,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"
|
||||
@@ -90,6 +89,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
|
||||
@@ -693,8 +693,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
|
||||
@@ -703,11 +701,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.
|
||||
|
||||
@@ -996,6 +995,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,422 @@
|
||||
+/*
|
||||
+ * 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;
|
||||
+}
|
||||
+
|
||||
+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;
|
||||
+
|
||||
+ spin_lock_bh(&hooks_lock);
|
||||
+ hlist_for_each_entry(hook, &hooks, list) {
|
||||
+ if (hook->ops.dev->ifindex != tuple->iifidx &&
|
||||
+ hook->ops.dev->ifindex != tuple->oifidx)
|
||||
+ 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_net(dev), 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
|
||||
@@ -6,7 +6,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>
|
||||
--- /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 */
|
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
|
||||
@@ -140,8 +140,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
|
||||
@@ -474,7 +474,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);
|
@ -0,0 +1,94 @@
|
||||
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
|
||||
@@ -487,12 +487,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
|
||||
@@ -3,8 +3,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
|
||||
@@ -2162,7 +2162,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
|
||||
@@ -714,7 +714,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),
|
||||
@@ -729,6 +729,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
|
||||
@@ -35,7 +35,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. */
|
||||
@@ -1025,7 +1025,7 @@ 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;
|
220
target/linux/generic/hack-5.4/662-remove_pfifo_fast.patch
Normal file
220
target/linux/generic/hack-5.4/662-remove_pfifo_fast.patch
Normal file
@ -0,0 +1,220 @@
|
||||
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
|
||||
@@ -612,207 +612,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))
|
||||
- return qdisc_drop_cpu(skb, qdisc, to_free);
|
||||
-
|
||||
- qdisc_qstats_atomic_qlen_inc(qdisc);
|
||||
- /* Note: skb can not be used after skb_array_produce(),
|
||||
- * so we better not use qdisc_qstats_cpu_backlog_inc()
|
||||
- */
|
||||
- this_cpu_add(qdisc->cpu_qstats->backlog, 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_qstats_cpu_backlog_dec(qdisc, skb);
|
||||
- qdisc_bstats_cpu_update(qdisc, skb);
|
||||
- qdisc_qstats_atomic_qlen_dec(qdisc);
|
||||
- }
|
||||
-
|
||||
- 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);
|
||||
- }
|
||||
-
|
||||
- for_each_possible_cpu(i) {
|
||||
- struct gnet_stats_queue *q = per_cpu_ptr(qdisc->cpu_qstats, i);
|
||||
-
|
||||
- q->backlog = 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);
|
||||
-
|
||||
static struct lock_class_key qdisc_tx_busylock;
|
||||
static struct lock_class_key qdisc_running_key;
|
||||
|
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
|
||||
@@ -209,6 +209,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_BCM_IPROC) += mdio-bcm-iproc.o
|
||||
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
|
||||
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o
|
||||
--- a/include/linux/platform_data/b53.h
|
||||
+++ b/include/linux/platform_data/b53.h
|
||||
@@ -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;
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user