mirror of https://github.com/hak5/openwrt-owl.git
kernel: add linux 4.9 support
Signed-off-by: Felix Fietkau <nbd@nbd.name> Signed-off-by: Tim Harvey <tharvey@gateworks.com> [fixes]owl
parent
7d00cfe9bb
commit
f791fb4af4
|
@ -4,9 +4,11 @@ LINUX_RELEASE?=1
|
||||||
|
|
||||||
LINUX_VERSION-3.18 = .43
|
LINUX_VERSION-3.18 = .43
|
||||||
LINUX_VERSION-4.4 = .46
|
LINUX_VERSION-4.4 = .46
|
||||||
|
LINUX_VERSION-4.9 = .8
|
||||||
|
|
||||||
LINUX_KERNEL_HASH-3.18.43 = 1236e8123a6ce537d5029232560966feed054ae31776fe8481dd7d18cdd5492c
|
LINUX_KERNEL_HASH-3.18.43 = 1236e8123a6ce537d5029232560966feed054ae31776fe8481dd7d18cdd5492c
|
||||||
LINUX_KERNEL_HASH-4.4.46 = bb944846c5901aa2cadaa20c3d953ec03ff707dc1178e6ac3851e98747872058
|
LINUX_KERNEL_HASH-4.4.46 = bb944846c5901aa2cadaa20c3d953ec03ff707dc1178e6ac3851e98747872058
|
||||||
|
LINUX_KERNEL_HASH-4.9.8 = 150bb7f2dd4849b5d21b8ccd8d05294a48229e1fcb93a22e7b806a79ec0b0e45
|
||||||
|
|
||||||
ifdef KERNEL_PATCHVER
|
ifdef KERNEL_PATCHVER
|
||||||
LINUX_VERSION:=$(KERNEL_PATCHVER)$(strip $(LINUX_VERSION-$(KERNEL_PATCHVER)))
|
LINUX_VERSION:=$(KERNEL_PATCHVER)$(strip $(LINUX_VERSION-$(KERNEL_PATCHVER)))
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,25 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Mon, 18 Jan 2016 12:27:49 +0100
|
||||||
|
Subject: [PATCH] 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>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/scripts/ld-version.sh
|
||||||
|
+++ b/scripts/ld-version.sh
|
||||||
|
@@ -1,5 +1,6 @@
|
||||||
|
-#!/usr/bin/awk -f
|
||||||
|
+#!/bin/sh
|
||||||
|
# extract linker version number from stdin and turn into single number
|
||||||
|
+exec awk '
|
||||||
|
{
|
||||||
|
gsub(".*\\)", "");
|
||||||
|
gsub(".*version ", "");
|
||||||
|
@@ -8,3 +9,4 @@
|
||||||
|
print a[1]*100000000 + a[2]*1000000 + a[3]*10000;
|
||||||
|
exit
|
||||||
|
}
|
||||||
|
+'
|
|
@ -0,0 +1,531 @@
|
||||||
|
Subject: 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>
|
||||||
|
|
||||||
|
--- a/include/net/netfilter/nf_conntrack_extend.h
|
||||||
|
+++ b/include/net/netfilter/nf_conntrack_extend.h
|
||||||
|
@@ -27,6 +27,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,
|
||||||
|
};
|
||||||
|
|
||||||
|
@@ -39,6 +42,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
|
||||||
|
@@ -114,6 +114,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
|
||||||
|
@@ -16,6 +16,9 @@ obj-$(CONFIG_NETFILTER_NETLINK_LOG) += n
|
||||||
|
# connection tracking
|
||||||
|
obj-$(CONFIG_NF_CONNTRACK) += nf_conntrack.o
|
||||||
|
|
||||||
|
+# optional conntrack route cache extension
|
||||||
|
+obj-$(CONFIG_NF_CONNTRACK_RTCACHE) += nf_conntrack_rtcache.o
|
||||||
|
+
|
||||||
|
# SCTP protocol connection tracking
|
||||||
|
obj-$(CONFIG_NF_CT_PROTO_DCCP) += nf_conntrack_proto_dccp.o
|
||||||
|
obj-$(CONFIG_NF_CT_PROTO_GRE) += nf_conntrack_proto_gre.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/net/netfilter/nf_conntrack_rtcache.c
|
||||||
|
@@ -0,0 +1,413 @@
|
||||||
|
+/* 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)
|
||||||
|
+{
|
||||||
|
+ if (nf_ct_is_untracked(ct))
|
||||||
|
+ return NULL;
|
||||||
|
+ 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->rt6i_node)
|
||||||
|
+ return (u32)rt->rt6i_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, 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 __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 = nf_register_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||||
|
+ if (ret < 0) {
|
||||||
|
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ ret = register_netdevice_notifier(&nf_rtcache_notifier);
|
||||||
|
+ if (ret) {
|
||||||
|
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||||
|
+ nf_ct_extend_unregister(&rtcache_extend);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ 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;
|
||||||
|
+
|
||||||
|
+ /* remove hooks so no new connections get rtcache extension */
|
||||||
|
+ nf_unregister_hooks(rtcache_ops, ARRAY_SIZE(rtcache_ops));
|
||||||
|
+
|
||||||
|
+ synchronize_net();
|
||||||
|
+
|
||||||
|
+ unregister_netdevice_notifier(&nf_rtcache_notifier);
|
||||||
|
+
|
||||||
|
+ rtnl_lock();
|
||||||
|
+
|
||||||
|
+ /* zap all conntracks with rtcache extension */
|
||||||
|
+ for_each_net(net)
|
||||||
|
+ nf_ct_iterate_cleanup(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,499 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Thu, 19 Jan 2017 03:45:10 +0100
|
||||||
|
Subject: [PATCH] bridge: multicast to unicast
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Implements an optional, per bridge port flag and feature to deliver
|
||||||
|
multicast packets to any host on the according port via unicast
|
||||||
|
individually. This is done by copying the packet per host and
|
||||||
|
changing the multicast destination MAC to a unicast one accordingly.
|
||||||
|
|
||||||
|
multicast-to-unicast works on top of the multicast snooping feature of
|
||||||
|
the bridge. Which means unicast copies are only delivered to hosts which
|
||||||
|
are interested in it and signalized this via IGMP/MLD reports
|
||||||
|
previously.
|
||||||
|
|
||||||
|
This feature is intended for interface types which have a more reliable
|
||||||
|
and/or efficient way to deliver unicast packets than broadcast ones
|
||||||
|
(e.g. wifi).
|
||||||
|
|
||||||
|
However, it should only be enabled on interfaces where no IGMPv2/MLDv1
|
||||||
|
report suppression takes place. This feature is disabled by default.
|
||||||
|
|
||||||
|
The initial patch and idea is from Felix Fietkau.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
[linus.luessing@c0d3.blue: various bug + style fixes, commit message]
|
||||||
|
Signed-off-by: Linus Lüssing <linus.luessing@c0d3.blue>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/linux/if_bridge.h
|
||||||
|
+++ b/include/linux/if_bridge.h
|
||||||
|
@@ -46,6 +46,7 @@ struct br_ip_list {
|
||||||
|
#define BR_LEARNING_SYNC BIT(9)
|
||||||
|
#define BR_PROXYARP_WIFI BIT(10)
|
||||||
|
#define BR_MCAST_FLOOD BIT(11)
|
||||||
|
+#define BR_MULTICAST_TO_UNICAST BIT(12)
|
||||||
|
|
||||||
|
#define BR_DEFAULT_AGEING_TIME (300 * HZ)
|
||||||
|
|
||||||
|
--- a/include/uapi/linux/if_link.h
|
||||||
|
+++ b/include/uapi/linux/if_link.h
|
||||||
|
@@ -319,6 +319,7 @@ enum {
|
||||||
|
IFLA_BRPORT_MULTICAST_ROUTER,
|
||||||
|
IFLA_BRPORT_PAD,
|
||||||
|
IFLA_BRPORT_MCAST_FLOOD,
|
||||||
|
+ IFLA_BRPORT_MCAST_TO_UCAST,
|
||||||
|
__IFLA_BRPORT_MAX
|
||||||
|
};
|
||||||
|
#define IFLA_BRPORT_MAX (__IFLA_BRPORT_MAX - 1)
|
||||||
|
--- a/net/bridge/br_forward.c
|
||||||
|
+++ b/net/bridge/br_forward.c
|
||||||
|
@@ -174,6 +174,29 @@ out:
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static void maybe_deliver_addr(struct net_bridge_port *p, struct sk_buff *skb,
|
||||||
|
+ const unsigned char *addr, bool local_orig)
|
||||||
|
+{
|
||||||
|
+ struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||||
|
+ const unsigned char *src = eth_hdr(skb)->h_source;
|
||||||
|
+
|
||||||
|
+ if (!should_deliver(p, skb))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ /* Even with hairpin, no soliloquies - prevent breaking IPv6 DAD */
|
||||||
|
+ if (skb->dev == p->dev && ether_addr_equal(src, addr))
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ skb = skb_copy(skb, GFP_ATOMIC);
|
||||||
|
+ if (!skb) {
|
||||||
|
+ dev->stats.tx_dropped++;
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ memcpy(eth_hdr(skb)->h_dest, addr, ETH_ALEN);
|
||||||
|
+ __br_forward(p, skb, local_orig);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* called under rcu_read_lock */
|
||||||
|
void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||||
|
enum br_pkt_type pkt_type, bool local_rcv, bool local_orig)
|
||||||
|
@@ -241,10 +264,20 @@ void br_multicast_flood(struct net_bridg
|
||||||
|
rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
|
||||||
|
NULL;
|
||||||
|
|
||||||
|
- port = (unsigned long)lport > (unsigned long)rport ?
|
||||||
|
- lport : rport;
|
||||||
|
+ if ((unsigned long)lport > (unsigned long)rport) {
|
||||||
|
+ port = lport;
|
||||||
|
+
|
||||||
|
+ if (p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST) {
|
||||||
|
+ maybe_deliver_addr(lport, skb, p->eth_addr,
|
||||||
|
+ local_orig);
|
||||||
|
+ goto delivered;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ port = rport;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
prev = maybe_deliver(prev, port, skb, local_orig);
|
||||||
|
+delivered:
|
||||||
|
if (IS_ERR(prev))
|
||||||
|
goto out;
|
||||||
|
if (prev == port)
|
||||||
|
--- a/net/bridge/br_mdb.c
|
||||||
|
+++ b/net/bridge/br_mdb.c
|
||||||
|
@@ -531,7 +531,7 @@ static int br_mdb_add_group(struct net_b
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- p = br_multicast_new_port_group(port, group, *pp, state);
|
||||||
|
+ p = br_multicast_new_port_group(port, group, *pp, state, NULL);
|
||||||
|
if (unlikely(!p))
|
||||||
|
return -ENOMEM;
|
||||||
|
rcu_assign_pointer(*pp, p);
|
||||||
|
--- a/net/bridge/br_multicast.c
|
||||||
|
+++ b/net/bridge/br_multicast.c
|
||||||
|
@@ -42,12 +42,14 @@ static void br_multicast_add_router(stru
|
||||||
|
static void br_ip4_multicast_leave_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
__be32 group,
|
||||||
|
- __u16 vid);
|
||||||
|
+ __u16 vid,
|
||||||
|
+ const unsigned char *src);
|
||||||
|
+
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static void br_ip6_multicast_leave_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
const struct in6_addr *group,
|
||||||
|
- __u16 vid);
|
||||||
|
+ __u16 vid, const unsigned char *src);
|
||||||
|
#endif
|
||||||
|
unsigned int br_mdb_rehash_seq;
|
||||||
|
|
||||||
|
@@ -658,7 +660,8 @@ struct net_bridge_port_group *br_multica
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
struct br_ip *group,
|
||||||
|
struct net_bridge_port_group __rcu *next,
|
||||||
|
- unsigned char flags)
|
||||||
|
+ unsigned char flags,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct net_bridge_port_group *p;
|
||||||
|
|
||||||
|
@@ -673,12 +676,39 @@ struct net_bridge_port_group *br_multica
|
||||||
|
hlist_add_head(&p->mglist, &port->mglist);
|
||||||
|
setup_timer(&p->timer, br_multicast_port_group_expired,
|
||||||
|
(unsigned long)p);
|
||||||
|
+
|
||||||
|
+ if ((port->flags & BR_MULTICAST_TO_UNICAST) && src) {
|
||||||
|
+ memcpy(p->eth_addr, src, ETH_ALEN);
|
||||||
|
+ p->flags |= MDB_PG_FLAGS_MCAST_TO_UCAST;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static bool br_port_group_equal(struct net_bridge_port_group *p,
|
||||||
|
+ struct net_bridge_port *port,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
+{
|
||||||
|
+ if (p->port != port)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ if (!(p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST) !=
|
||||||
|
+ !(port->flags & BR_MULTICAST_TO_UNICAST))
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ if (!(p->flags & MDB_PG_FLAGS_MCAST_TO_UCAST))
|
||||||
|
+ return true;
|
||||||
|
+
|
||||||
|
+ if (!src)
|
||||||
|
+ return false;
|
||||||
|
+
|
||||||
|
+ return ether_addr_equal(src, p->eth_addr);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int br_multicast_add_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
- struct br_ip *group)
|
||||||
|
+ struct br_ip *group,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct net_bridge_mdb_entry *mp;
|
||||||
|
struct net_bridge_port_group *p;
|
||||||
|
@@ -705,13 +735,13 @@ static int br_multicast_add_group(struct
|
||||||
|
for (pp = &mp->ports;
|
||||||
|
(p = mlock_dereference(*pp, br)) != NULL;
|
||||||
|
pp = &p->next) {
|
||||||
|
- if (p->port == port)
|
||||||
|
+ if (br_port_group_equal(p, port, src))
|
||||||
|
goto found;
|
||||||
|
if ((unsigned long)p->port < (unsigned long)port)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
- p = br_multicast_new_port_group(port, group, *pp, 0);
|
||||||
|
+ p = br_multicast_new_port_group(port, group, *pp, 0, src);
|
||||||
|
if (unlikely(!p))
|
||||||
|
goto err;
|
||||||
|
rcu_assign_pointer(*pp, p);
|
||||||
|
@@ -730,7 +760,8 @@ err:
|
||||||
|
static int br_ip4_multicast_add_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
__be32 group,
|
||||||
|
- __u16 vid)
|
||||||
|
+ __u16 vid,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct br_ip br_group;
|
||||||
|
|
||||||
|
@@ -741,14 +772,15 @@ static int br_ip4_multicast_add_group(st
|
||||||
|
br_group.proto = htons(ETH_P_IP);
|
||||||
|
br_group.vid = vid;
|
||||||
|
|
||||||
|
- return br_multicast_add_group(br, port, &br_group);
|
||||||
|
+ return br_multicast_add_group(br, port, &br_group, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static int br_ip6_multicast_add_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
const struct in6_addr *group,
|
||||||
|
- __u16 vid)
|
||||||
|
+ __u16 vid,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct br_ip br_group;
|
||||||
|
|
||||||
|
@@ -759,7 +791,7 @@ static int br_ip6_multicast_add_group(st
|
||||||
|
br_group.proto = htons(ETH_P_IPV6);
|
||||||
|
br_group.vid = vid;
|
||||||
|
|
||||||
|
- return br_multicast_add_group(br, port, &br_group);
|
||||||
|
+ return br_multicast_add_group(br, port, &br_group, src);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -1028,6 +1060,7 @@ static int br_ip4_multicast_igmp3_report
|
||||||
|
struct sk_buff *skb,
|
||||||
|
u16 vid)
|
||||||
|
{
|
||||||
|
+ const unsigned char *src;
|
||||||
|
struct igmpv3_report *ih;
|
||||||
|
struct igmpv3_grec *grec;
|
||||||
|
int i;
|
||||||
|
@@ -1068,12 +1101,14 @@ static int br_ip4_multicast_igmp3_report
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ src = eth_hdr(skb)->h_source;
|
||||||
|
if ((type == IGMPV3_CHANGE_TO_INCLUDE ||
|
||||||
|
type == IGMPV3_MODE_IS_INCLUDE) &&
|
||||||
|
ntohs(grec->grec_nsrcs) == 0) {
|
||||||
|
- br_ip4_multicast_leave_group(br, port, group, vid);
|
||||||
|
+ br_ip4_multicast_leave_group(br, port, group, vid, src);
|
||||||
|
} else {
|
||||||
|
- err = br_ip4_multicast_add_group(br, port, group, vid);
|
||||||
|
+ err = br_ip4_multicast_add_group(br, port, group, vid,
|
||||||
|
+ src);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -1088,6 +1123,7 @@ static int br_ip6_multicast_mld2_report(
|
||||||
|
struct sk_buff *skb,
|
||||||
|
u16 vid)
|
||||||
|
{
|
||||||
|
+ const unsigned char *src = eth_hdr(skb)->h_source;
|
||||||
|
struct icmp6hdr *icmp6h;
|
||||||
|
struct mld2_grec *grec;
|
||||||
|
int i;
|
||||||
|
@@ -1139,10 +1175,11 @@ static int br_ip6_multicast_mld2_report(
|
||||||
|
grec->grec_type == MLD2_MODE_IS_INCLUDE) &&
|
||||||
|
ntohs(*nsrcs) == 0) {
|
||||||
|
br_ip6_multicast_leave_group(br, port, &grec->grec_mca,
|
||||||
|
- vid);
|
||||||
|
+ vid, src);
|
||||||
|
} else {
|
||||||
|
err = br_ip6_multicast_add_group(br, port,
|
||||||
|
- &grec->grec_mca, vid);
|
||||||
|
+ &grec->grec_mca, vid,
|
||||||
|
+ src);
|
||||||
|
if (err)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
@@ -1458,7 +1495,8 @@ br_multicast_leave_group(struct net_brid
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
struct br_ip *group,
|
||||||
|
struct bridge_mcast_other_query *other_query,
|
||||||
|
- struct bridge_mcast_own_query *own_query)
|
||||||
|
+ struct bridge_mcast_own_query *own_query,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct net_bridge_mdb_htable *mdb;
|
||||||
|
struct net_bridge_mdb_entry *mp;
|
||||||
|
@@ -1482,7 +1520,7 @@ br_multicast_leave_group(struct net_brid
|
||||||
|
for (pp = &mp->ports;
|
||||||
|
(p = mlock_dereference(*pp, br)) != NULL;
|
||||||
|
pp = &p->next) {
|
||||||
|
- if (p->port != port)
|
||||||
|
+ if (!br_port_group_equal(p, port, src))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
rcu_assign_pointer(*pp, p->next);
|
||||||
|
@@ -1513,7 +1551,7 @@ br_multicast_leave_group(struct net_brid
|
||||||
|
for (p = mlock_dereference(mp->ports, br);
|
||||||
|
p != NULL;
|
||||||
|
p = mlock_dereference(p->next, br)) {
|
||||||
|
- if (p->port != port)
|
||||||
|
+ if (!br_port_group_equal(p, port, src))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (!hlist_unhashed(&p->mglist) &&
|
||||||
|
@@ -1564,7 +1602,8 @@ out:
|
||||||
|
static void br_ip4_multicast_leave_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
__be32 group,
|
||||||
|
- __u16 vid)
|
||||||
|
+ __u16 vid,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct br_ip br_group;
|
||||||
|
struct bridge_mcast_own_query *own_query;
|
||||||
|
@@ -1579,14 +1618,15 @@ static void br_ip4_multicast_leave_group
|
||||||
|
br_group.vid = vid;
|
||||||
|
|
||||||
|
br_multicast_leave_group(br, port, &br_group, &br->ip4_other_query,
|
||||||
|
- own_query);
|
||||||
|
+ own_query, src);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if IS_ENABLED(CONFIG_IPV6)
|
||||||
|
static void br_ip6_multicast_leave_group(struct net_bridge *br,
|
||||||
|
struct net_bridge_port *port,
|
||||||
|
const struct in6_addr *group,
|
||||||
|
- __u16 vid)
|
||||||
|
+ __u16 vid,
|
||||||
|
+ const unsigned char *src)
|
||||||
|
{
|
||||||
|
struct br_ip br_group;
|
||||||
|
struct bridge_mcast_own_query *own_query;
|
||||||
|
@@ -1601,7 +1641,7 @@ static void br_ip6_multicast_leave_group
|
||||||
|
br_group.vid = vid;
|
||||||
|
|
||||||
|
br_multicast_leave_group(br, port, &br_group, &br->ip6_other_query,
|
||||||
|
- own_query);
|
||||||
|
+ own_query, src);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@@ -1644,6 +1684,7 @@ static int br_multicast_ipv4_rcv(struct
|
||||||
|
u16 vid)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb_trimmed = NULL;
|
||||||
|
+ const unsigned char *src;
|
||||||
|
struct igmphdr *ih;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
@@ -1659,13 +1700,14 @@ static int br_multicast_ipv4_rcv(struct
|
||||||
|
}
|
||||||
|
|
||||||
|
ih = igmp_hdr(skb);
|
||||||
|
+ src = eth_hdr(skb)->h_source;
|
||||||
|
BR_INPUT_SKB_CB(skb)->igmp = ih->type;
|
||||||
|
|
||||||
|
switch (ih->type) {
|
||||||
|
case IGMP_HOST_MEMBERSHIP_REPORT:
|
||||||
|
case IGMPV2_HOST_MEMBERSHIP_REPORT:
|
||||||
|
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
|
||||||
|
- err = br_ip4_multicast_add_group(br, port, ih->group, vid);
|
||||||
|
+ err = br_ip4_multicast_add_group(br, port, ih->group, vid, src);
|
||||||
|
break;
|
||||||
|
case IGMPV3_HOST_MEMBERSHIP_REPORT:
|
||||||
|
err = br_ip4_multicast_igmp3_report(br, port, skb_trimmed, vid);
|
||||||
|
@@ -1674,7 +1716,7 @@ static int br_multicast_ipv4_rcv(struct
|
||||||
|
err = br_ip4_multicast_query(br, port, skb_trimmed, vid);
|
||||||
|
break;
|
||||||
|
case IGMP_HOST_LEAVE_MESSAGE:
|
||||||
|
- br_ip4_multicast_leave_group(br, port, ih->group, vid);
|
||||||
|
+ br_ip4_multicast_leave_group(br, port, ih->group, vid, src);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1694,6 +1736,7 @@ static int br_multicast_ipv6_rcv(struct
|
||||||
|
u16 vid)
|
||||||
|
{
|
||||||
|
struct sk_buff *skb_trimmed = NULL;
|
||||||
|
+ const unsigned char *src;
|
||||||
|
struct mld_msg *mld;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
@@ -1713,8 +1756,10 @@ static int br_multicast_ipv6_rcv(struct
|
||||||
|
|
||||||
|
switch (mld->mld_type) {
|
||||||
|
case ICMPV6_MGM_REPORT:
|
||||||
|
+ src = eth_hdr(skb)->h_source;
|
||||||
|
BR_INPUT_SKB_CB(skb)->mrouters_only = 1;
|
||||||
|
- err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid);
|
||||||
|
+ err = br_ip6_multicast_add_group(br, port, &mld->mld_mca, vid,
|
||||||
|
+ src);
|
||||||
|
break;
|
||||||
|
case ICMPV6_MLD2_REPORT:
|
||||||
|
err = br_ip6_multicast_mld2_report(br, port, skb_trimmed, vid);
|
||||||
|
@@ -1723,7 +1768,8 @@ static int br_multicast_ipv6_rcv(struct
|
||||||
|
err = br_ip6_multicast_query(br, port, skb_trimmed, vid);
|
||||||
|
break;
|
||||||
|
case ICMPV6_MGM_REDUCTION:
|
||||||
|
- br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid);
|
||||||
|
+ src = eth_hdr(skb)->h_source;
|
||||||
|
+ br_ip6_multicast_leave_group(br, port, &mld->mld_mca, vid, src);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/net/bridge/br_netlink.c
|
||||||
|
+++ b/net/bridge/br_netlink.c
|
||||||
|
@@ -123,6 +123,7 @@ static inline size_t br_port_info_size(v
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_GUARD */
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_PROTECT */
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */
|
||||||
|
+ + nla_total_size(1) /* IFLA_BRPORT_MCAST_TO_UCAST */
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_LEARNING */
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */
|
||||||
|
+ nla_total_size(1) /* IFLA_BRPORT_PROXYARP */
|
||||||
|
@@ -173,6 +174,8 @@ static int br_port_fill_attrs(struct sk_
|
||||||
|
!!(p->flags & BR_ROOT_BLOCK)) ||
|
||||||
|
nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE,
|
||||||
|
!!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
|
||||||
|
+ nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST,
|
||||||
|
+ !!(p->flags & BR_MULTICAST_TO_UNICAST)) ||
|
||||||
|
nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
|
||||||
|
nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD,
|
||||||
|
!!(p->flags & BR_FLOOD)) ||
|
||||||
|
@@ -586,6 +589,7 @@ static const struct nla_policy br_port_p
|
||||||
|
[IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 },
|
||||||
|
[IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
|
||||||
|
[IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 },
|
||||||
|
+ [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Change the state of the port and notify spanning tree */
|
||||||
|
@@ -636,6 +640,7 @@ static int br_setport(struct net_bridge_
|
||||||
|
br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
|
||||||
|
br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
|
||||||
|
br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
|
||||||
|
+ br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST);
|
||||||
|
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
|
||||||
|
br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
|
||||||
|
|
||||||
|
--- a/net/bridge/br_private.h
|
||||||
|
+++ b/net/bridge/br_private.h
|
||||||
|
@@ -166,8 +166,9 @@ struct net_bridge_fdb_entry
|
||||||
|
struct rcu_head rcu;
|
||||||
|
};
|
||||||
|
|
||||||
|
-#define MDB_PG_FLAGS_PERMANENT BIT(0)
|
||||||
|
-#define MDB_PG_FLAGS_OFFLOAD BIT(1)
|
||||||
|
+#define MDB_PG_FLAGS_PERMANENT BIT(0)
|
||||||
|
+#define MDB_PG_FLAGS_OFFLOAD BIT(1)
|
||||||
|
+#define MDB_PG_FLAGS_MCAST_TO_UCAST BIT(2)
|
||||||
|
|
||||||
|
struct net_bridge_port_group {
|
||||||
|
struct net_bridge_port *port;
|
||||||
|
@@ -177,6 +178,7 @@ struct net_bridge_port_group {
|
||||||
|
struct timer_list timer;
|
||||||
|
struct br_ip addr;
|
||||||
|
unsigned char flags;
|
||||||
|
+ unsigned char eth_addr[ETH_ALEN];
|
||||||
|
};
|
||||||
|
|
||||||
|
struct net_bridge_mdb_entry
|
||||||
|
@@ -591,7 +593,7 @@ void br_multicast_free_pg(struct rcu_hea
|
||||||
|
struct net_bridge_port_group *
|
||||||
|
br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
|
||||||
|
struct net_bridge_port_group __rcu *next,
|
||||||
|
- unsigned char flags);
|
||||||
|
+ unsigned char flags, const unsigned char *src);
|
||||||
|
void br_mdb_init(void);
|
||||||
|
void br_mdb_uninit(void);
|
||||||
|
void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
|
||||||
|
--- a/net/bridge/br_sysfs_if.c
|
||||||
|
+++ b/net/bridge/br_sysfs_if.c
|
||||||
|
@@ -188,6 +188,7 @@ static BRPORT_ATTR(multicast_router, S_I
|
||||||
|
store_multicast_router);
|
||||||
|
|
||||||
|
BRPORT_ATTR_FLAG(multicast_fast_leave, BR_MULTICAST_FAST_LEAVE);
|
||||||
|
+BRPORT_ATTR_FLAG(multicast_to_unicast, BR_MULTICAST_TO_UNICAST);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static const struct brport_attribute *brport_attrs[] = {
|
||||||
|
@@ -214,6 +215,7 @@ static const struct brport_attribute *br
|
||||||
|
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||||
|
&brport_attr_multicast_router,
|
||||||
|
&brport_attr_multicast_fast_leave,
|
||||||
|
+ &brport_attr_multicast_to_unicast,
|
||||||
|
#endif
|
||||||
|
&brport_attr_proxyarp,
|
||||||
|
&brport_attr_proxyarp_wifi,
|
|
@ -0,0 +1,69 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Sat, 28 Jan 2017 15:15:42 +0100
|
||||||
|
Subject: [PATCH] net: add devm version of alloc_etherdev_mqs function
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
This patch adds devm_alloc_etherdev_mqs function and devm_alloc_etherdev
|
||||||
|
macro. These can be used for simpler netdev allocation without having to
|
||||||
|
care about calling free_netdev.
|
||||||
|
|
||||||
|
Thanks to this change drivers, their error paths and removal paths may
|
||||||
|
get simpler by a bit.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/linux/etherdevice.h
|
||||||
|
+++ b/include/linux/etherdevice.h
|
||||||
|
@@ -54,6 +54,11 @@ struct net_device *alloc_etherdev_mqs(in
|
||||||
|
#define alloc_etherdev(sizeof_priv) alloc_etherdev_mq(sizeof_priv, 1)
|
||||||
|
#define alloc_etherdev_mq(sizeof_priv, count) alloc_etherdev_mqs(sizeof_priv, count, count)
|
||||||
|
|
||||||
|
+struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
|
||||||
|
+ unsigned int txqs,
|
||||||
|
+ unsigned int rxqs);
|
||||||
|
+#define devm_alloc_etherdev(dev, sizeof_priv) devm_alloc_etherdev_mqs(dev, sizeof_priv, 1, 1)
|
||||||
|
+
|
||||||
|
struct sk_buff **eth_gro_receive(struct sk_buff **head,
|
||||||
|
struct sk_buff *skb);
|
||||||
|
int eth_gro_complete(struct sk_buff *skb, int nhoff);
|
||||||
|
--- a/net/ethernet/eth.c
|
||||||
|
+++ b/net/ethernet/eth.c
|
||||||
|
@@ -390,6 +390,34 @@ struct net_device *alloc_etherdev_mqs(in
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL(alloc_etherdev_mqs);
|
||||||
|
|
||||||
|
+static void devm_free_netdev(struct device *dev, void *res)
|
||||||
|
+{
|
||||||
|
+ free_netdev(*(struct net_device **)res);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+struct net_device *devm_alloc_etherdev_mqs(struct device *dev, int sizeof_priv,
|
||||||
|
+ unsigned int txqs, unsigned int rxqs)
|
||||||
|
+{
|
||||||
|
+ struct net_device **dr;
|
||||||
|
+ struct net_device *netdev;
|
||||||
|
+
|
||||||
|
+ dr = devres_alloc(devm_free_netdev, sizeof(*dr), GFP_KERNEL);
|
||||||
|
+ if (!dr)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ netdev = alloc_etherdev_mqs(sizeof_priv, txqs, rxqs);
|
||||||
|
+ if (!netdev) {
|
||||||
|
+ devres_free(dr);
|
||||||
|
+ return NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ *dr = netdev;
|
||||||
|
+ devres_add(dev, dr);
|
||||||
|
+
|
||||||
|
+ return netdev;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(devm_alloc_etherdev_mqs);
|
||||||
|
+
|
||||||
|
ssize_t sysfs_format_mac(char *buf, const unsigned char *addr, int len)
|
||||||
|
{
|
||||||
|
return scnprintf(buf, PAGE_SIZE, "%*phC\n", len, addr);
|
|
@ -0,0 +1,82 @@
|
||||||
|
From 854826c9d526fd81077742c3b000e3f7fcaef3ce Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 20 Sep 2016 10:36:14 +0200
|
||||||
|
Subject: [PATCH] ubifs: Drop softlimit and delta fields from struct ubifs_wbuf
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Values of these fields are set during init and never modified. They are
|
||||||
|
used (read) in a single function only. There isn't really any reason to
|
||||||
|
keep them in a struct. It only makes struct just a bit bigger without
|
||||||
|
any visible gain.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||||
|
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||||
|
---
|
||||||
|
fs/ubifs/io.c | 18 ++++++++++--------
|
||||||
|
fs/ubifs/ubifs.h | 5 -----
|
||||||
|
2 files changed, 10 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
--- a/fs/ubifs/io.c
|
||||||
|
+++ b/fs/ubifs/io.c
|
||||||
|
@@ -452,16 +452,22 @@ static enum hrtimer_restart wbuf_timer_c
|
||||||
|
*/
|
||||||
|
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
|
||||||
|
{
|
||||||
|
+ ktime_t softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||||
|
+ unsigned long long delta;
|
||||||
|
+
|
||||||
|
+ delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||||
|
+ delta *= 1000000000ULL;
|
||||||
|
+
|
||||||
|
ubifs_assert(!hrtimer_active(&wbuf->timer));
|
||||||
|
+ ubifs_assert(delta <= ULONG_MAX);
|
||||||
|
|
||||||
|
if (wbuf->no_timer)
|
||||||
|
return;
|
||||||
|
dbg_io("set timer for jhead %s, %llu-%llu millisecs",
|
||||||
|
dbg_jhead(wbuf->jhead),
|
||||||
|
- div_u64(ktime_to_ns(wbuf->softlimit), USEC_PER_SEC),
|
||||||
|
- div_u64(ktime_to_ns(wbuf->softlimit) + wbuf->delta,
|
||||||
|
- USEC_PER_SEC));
|
||||||
|
- hrtimer_start_range_ns(&wbuf->timer, wbuf->softlimit, wbuf->delta,
|
||||||
|
+ div_u64(ktime_to_ns(softlimit), USEC_PER_SEC),
|
||||||
|
+ div_u64(ktime_to_ns(softlimit) + delta, USEC_PER_SEC));
|
||||||
|
+ hrtimer_start_range_ns(&wbuf->timer, softlimit, delta,
|
||||||
|
HRTIMER_MODE_REL);
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -1059,10 +1065,6 @@ int ubifs_wbuf_init(struct ubifs_info *c
|
||||||
|
|
||||||
|
hrtimer_init(&wbuf->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||||
|
wbuf->timer.function = wbuf_timer_callback_nolock;
|
||||||
|
- wbuf->softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||||
|
- wbuf->delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||||
|
- wbuf->delta *= 1000000000ULL;
|
||||||
|
- ubifs_assert(wbuf->delta <= ULONG_MAX);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/fs/ubifs/ubifs.h
|
||||||
|
+++ b/fs/ubifs/ubifs.h
|
||||||
|
@@ -645,9 +645,6 @@ typedef int (*ubifs_lpt_scan_callback)(s
|
||||||
|
* @io_mutex: serializes write-buffer I/O
|
||||||
|
* @lock: serializes @buf, @lnum, @offs, @avail, @used, @next_ino and @inodes
|
||||||
|
* fields
|
||||||
|
- * @softlimit: soft write-buffer timeout interval
|
||||||
|
- * @delta: hard and soft timeouts delta (the timer expire interval is @softlimit
|
||||||
|
- * and @softlimit + @delta)
|
||||||
|
* @timer: write-buffer timer
|
||||||
|
* @no_timer: non-zero if this write-buffer does not have a timer
|
||||||
|
* @need_sync: non-zero if the timer expired and the wbuf needs sync'ing
|
||||||
|
@@ -676,8 +673,6 @@ struct ubifs_wbuf {
|
||||||
|
int (*sync_callback)(struct ubifs_info *c, int lnum, int free, int pad);
|
||||||
|
struct mutex io_mutex;
|
||||||
|
spinlock_t lock;
|
||||||
|
- ktime_t softlimit;
|
||||||
|
- unsigned long long delta;
|
||||||
|
struct hrtimer timer;
|
||||||
|
unsigned int no_timer:1;
|
||||||
|
unsigned int need_sync:1;
|
|
@ -0,0 +1,66 @@
|
||||||
|
From 1b7fc2c0069f3864a3dda15430b7aded31c0bfcc Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 20 Sep 2016 10:36:15 +0200
|
||||||
|
Subject: [PATCH] ubifs: Use dirty_writeback_interval value for wbuf timer
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Right now wbuf timer has hardcoded timeouts and there is no place for
|
||||||
|
manual adjustments. Some projects / cases many need that though. Few
|
||||||
|
file systems allow doing that by respecting dirty_writeback_interval
|
||||||
|
that can be set using sysctl (dirty_writeback_centisecs).
|
||||||
|
|
||||||
|
Lowering dirty_writeback_interval could be some way of dealing with user
|
||||||
|
space apps lacking proper fsyncs. This is definitely *not* a perfect
|
||||||
|
solution but we don't have ideal (user space) world. There were already
|
||||||
|
advanced discussions on this matter, mostly when ext4 was introduced and
|
||||||
|
it wasn't behaving as ext3. Anyway, the final decision was to add some
|
||||||
|
hacks to the ext4, as trying to fix whole user space or adding new API
|
||||||
|
was pointless.
|
||||||
|
|
||||||
|
We can't (and shouldn't?) just follow ext4. We can't e.g. sync on close
|
||||||
|
as this would cause too many commits and flash wearing. On the other
|
||||||
|
hand we still should allow some trade-off between -o sync and default
|
||||||
|
wbuf timeout. Respecting dirty_writeback_interval should allow some sane
|
||||||
|
cutomizations if used warily.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Boris Brezillon <boris.brezillon@free-electrons.com>
|
||||||
|
Signed-off-by: Richard Weinberger <richard@nod.at>
|
||||||
|
---
|
||||||
|
fs/ubifs/io.c | 8 ++++----
|
||||||
|
fs/ubifs/ubifs.h | 4 ----
|
||||||
|
2 files changed, 4 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
--- a/fs/ubifs/io.c
|
||||||
|
+++ b/fs/ubifs/io.c
|
||||||
|
@@ -452,11 +452,11 @@ static enum hrtimer_restart wbuf_timer_c
|
||||||
|
*/
|
||||||
|
static void new_wbuf_timer_nolock(struct ubifs_wbuf *wbuf)
|
||||||
|
{
|
||||||
|
- ktime_t softlimit = ktime_set(WBUF_TIMEOUT_SOFTLIMIT, 0);
|
||||||
|
- unsigned long long delta;
|
||||||
|
+ ktime_t softlimit = ms_to_ktime(dirty_writeback_interval * 10);
|
||||||
|
+ unsigned long long delta = dirty_writeback_interval;
|
||||||
|
|
||||||
|
- delta = WBUF_TIMEOUT_HARDLIMIT - WBUF_TIMEOUT_SOFTLIMIT;
|
||||||
|
- delta *= 1000000000ULL;
|
||||||
|
+ /* centi to milli, milli to nano, then 10% */
|
||||||
|
+ delta *= 10ULL * NSEC_PER_MSEC / 10ULL;
|
||||||
|
|
||||||
|
ubifs_assert(!hrtimer_active(&wbuf->timer));
|
||||||
|
ubifs_assert(delta <= ULONG_MAX);
|
||||||
|
--- a/fs/ubifs/ubifs.h
|
||||||
|
+++ b/fs/ubifs/ubifs.h
|
||||||
|
@@ -83,10 +83,6 @@
|
||||||
|
*/
|
||||||
|
#define BGT_NAME_PATTERN "ubifs_bgt%d_%d"
|
||||||
|
|
||||||
|
-/* Write-buffer synchronization timeout interval in seconds */
|
||||||
|
-#define WBUF_TIMEOUT_SOFTLIMIT 3
|
||||||
|
-#define WBUF_TIMEOUT_HARDLIMIT 5
|
||||||
|
-
|
||||||
|
/* Maximum possible inode number (only 32-bit inodes are supported now) */
|
||||||
|
#define MAX_INUM 0xFFFFFFFF
|
||||||
|
|
|
@ -0,0 +1,70 @@
|
||||||
|
From: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Date: Mon, 19 Dec 2016 14:20:56 +0000
|
||||||
|
Subject: [PATCH] MIPS: Introduce irq_stack
|
||||||
|
|
||||||
|
Allocate a per-cpu irq stack for use within interrupt handlers.
|
||||||
|
|
||||||
|
Also add a utility function on_irq_stack to determine if a given stack
|
||||||
|
pointer is within the irq stack for that cpu.
|
||||||
|
|
||||||
|
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/include/asm/irq.h
|
||||||
|
+++ b/arch/mips/include/asm/irq.h
|
||||||
|
@@ -17,6 +17,18 @@
|
||||||
|
|
||||||
|
#include <irq.h>
|
||||||
|
|
||||||
|
+#define IRQ_STACK_SIZE THREAD_SIZE
|
||||||
|
+
|
||||||
|
+extern void *irq_stack[NR_CPUS];
|
||||||
|
+
|
||||||
|
+static inline bool on_irq_stack(int cpu, unsigned long sp)
|
||||||
|
+{
|
||||||
|
+ unsigned long low = (unsigned long)irq_stack[cpu];
|
||||||
|
+ unsigned long high = low + IRQ_STACK_SIZE;
|
||||||
|
+
|
||||||
|
+ return (low <= sp && sp <= high);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_I8259
|
||||||
|
static inline int irq_canonicalize(int irq)
|
||||||
|
{
|
||||||
|
--- a/arch/mips/kernel/asm-offsets.c
|
||||||
|
+++ b/arch/mips/kernel/asm-offsets.c
|
||||||
|
@@ -102,6 +102,7 @@ void output_thread_info_defines(void)
|
||||||
|
OFFSET(TI_REGS, thread_info, regs);
|
||||||
|
DEFINE(_THREAD_SIZE, THREAD_SIZE);
|
||||||
|
DEFINE(_THREAD_MASK, THREAD_MASK);
|
||||||
|
+ DEFINE(_IRQ_STACK_SIZE, IRQ_STACK_SIZE);
|
||||||
|
BLANK();
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/irq.c
|
||||||
|
+++ b/arch/mips/kernel/irq.c
|
||||||
|
@@ -25,6 +25,8 @@
|
||||||
|
#include <linux/atomic.h>
|
||||||
|
#include <asm/uaccess.h>
|
||||||
|
|
||||||
|
+void *irq_stack[NR_CPUS];
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* 'what should we do if we get a hw irq event on an illegal vector'.
|
||||||
|
* each architecture has to answer this themselves.
|
||||||
|
@@ -58,6 +60,15 @@ void __init init_IRQ(void)
|
||||||
|
clear_c0_status(ST0_IM);
|
||||||
|
|
||||||
|
arch_init_irq();
|
||||||
|
+
|
||||||
|
+ for_each_possible_cpu(i) {
|
||||||
|
+ int irq_pages = IRQ_STACK_SIZE / PAGE_SIZE;
|
||||||
|
+ void *s = (void *)__get_free_pages(GFP_KERNEL, irq_pages);
|
||||||
|
+
|
||||||
|
+ irq_stack[i] = s;
|
||||||
|
+ pr_debug("CPU%d IRQ stack at 0x%p - 0x%p\n", i,
|
||||||
|
+ irq_stack[i], irq_stack[i] + IRQ_STACK_SIZE);
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef CONFIG_DEBUG_STACKOVERFLOW
|
|
@ -0,0 +1,42 @@
|
||||||
|
From: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Date: Mon, 19 Dec 2016 14:20:57 +0000
|
||||||
|
Subject: [PATCH] MIPS: Stack unwinding while on IRQ stack
|
||||||
|
|
||||||
|
Within unwind stack, check if the stack pointer being unwound is within
|
||||||
|
the CPU's irq_stack and if so use that page rather than the task's stack
|
||||||
|
page.
|
||||||
|
|
||||||
|
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/process.c
|
||||||
|
+++ b/arch/mips/kernel/process.c
|
||||||
|
@@ -33,6 +33,7 @@
|
||||||
|
#include <asm/dsemul.h>
|
||||||
|
#include <asm/dsp.h>
|
||||||
|
#include <asm/fpu.h>
|
||||||
|
+#include <asm/irq.h>
|
||||||
|
#include <asm/msa.h>
|
||||||
|
#include <asm/pgtable.h>
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
@@ -511,7 +512,19 @@ EXPORT_SYMBOL(unwind_stack_by_address);
|
||||||
|
unsigned long unwind_stack(struct task_struct *task, unsigned long *sp,
|
||||||
|
unsigned long pc, unsigned long *ra)
|
||||||
|
{
|
||||||
|
- unsigned long stack_page = (unsigned long)task_stack_page(task);
|
||||||
|
+ unsigned long stack_page = 0;
|
||||||
|
+ int cpu;
|
||||||
|
+
|
||||||
|
+ for_each_possible_cpu(cpu) {
|
||||||
|
+ if (on_irq_stack(cpu, *sp)) {
|
||||||
|
+ stack_page = (unsigned long)irq_stack[cpu];
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!stack_page)
|
||||||
|
+ stack_page = (unsigned long)task_stack_page(task);
|
||||||
|
+
|
||||||
|
return unwind_stack_by_address(stack_page, sp, pc, ra);
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,48 @@
|
||||||
|
From: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Date: Mon, 19 Dec 2016 14:20:58 +0000
|
||||||
|
Subject: [PATCH] MIPS: Only change $28 to thread_info if coming from user
|
||||||
|
mode
|
||||||
|
|
||||||
|
The SAVE_SOME macro is used to save the execution context on all
|
||||||
|
exceptions.
|
||||||
|
If an exception occurs while executing user code, the stack is switched
|
||||||
|
to the kernel's stack for the current task, and register $28 is switched
|
||||||
|
to point to the current_thread_info, which is at the bottom of the stack
|
||||||
|
region.
|
||||||
|
If the exception occurs while executing kernel code, the stack is left,
|
||||||
|
and this change ensures that register $28 is not updated. This is the
|
||||||
|
correct behaviour when the kernel can be executing on the separate irq
|
||||||
|
stack, because the thread_info will not be at the base of it.
|
||||||
|
|
||||||
|
With this change, register $28 is only switched to it's kernel
|
||||||
|
conventional usage of the currrent thread info pointer at the point at
|
||||||
|
which execution enters kernel space. Doing it on every exception was
|
||||||
|
redundant, but OK without an IRQ stack, but will be erroneous once that
|
||||||
|
is introduced.
|
||||||
|
|
||||||
|
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Reviewed-by: Maciej W. Rozycki <macro@imgtec.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/include/asm/stackframe.h
|
||||||
|
+++ b/arch/mips/include/asm/stackframe.h
|
||||||
|
@@ -216,12 +216,19 @@
|
||||||
|
LONG_S $25, PT_R25(sp)
|
||||||
|
LONG_S $28, PT_R28(sp)
|
||||||
|
LONG_S $31, PT_R31(sp)
|
||||||
|
+
|
||||||
|
+ /* Set thread_info if we're coming from user mode */
|
||||||
|
+ mfc0 k0, CP0_STATUS
|
||||||
|
+ sll k0, 3 /* extract cu0 bit */
|
||||||
|
+ bltz k0, 9f
|
||||||
|
+
|
||||||
|
ori $28, sp, _THREAD_MASK
|
||||||
|
xori $28, _THREAD_MASK
|
||||||
|
#ifdef CONFIG_CPU_CAVIUM_OCTEON
|
||||||
|
.set mips64
|
||||||
|
pref 0, 0($28) /* Prefetch the current pointer */
|
||||||
|
#endif
|
||||||
|
+9:
|
||||||
|
.set pop
|
||||||
|
.endm
|
||||||
|
|
|
@ -0,0 +1,116 @@
|
||||||
|
From: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Date: Mon, 19 Dec 2016 14:20:59 +0000
|
||||||
|
Subject: [PATCH] MIPS: Switch to the irq_stack in interrupts
|
||||||
|
|
||||||
|
When enterring interrupt context via handle_int or except_vec_vi, switch
|
||||||
|
to the irq_stack of the current CPU if it is not already in use.
|
||||||
|
|
||||||
|
The current stack pointer is masked with the thread size and compared to
|
||||||
|
the base or the irq stack. If it does not match then the stack pointer
|
||||||
|
is set to the top of that stack, otherwise this is a nested irq being
|
||||||
|
handled on the irq stack so the stack pointer should be left as it was.
|
||||||
|
|
||||||
|
The in-use stack pointer is placed in the callee saved register s1. It
|
||||||
|
will be saved to the stack when plat_irq_dispatch is invoked and can be
|
||||||
|
restored once control returns here.
|
||||||
|
|
||||||
|
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/genex.S
|
||||||
|
+++ b/arch/mips/kernel/genex.S
|
||||||
|
@@ -187,9 +187,44 @@ NESTED(handle_int, PT_SIZE, sp)
|
||||||
|
|
||||||
|
LONG_L s0, TI_REGS($28)
|
||||||
|
LONG_S sp, TI_REGS($28)
|
||||||
|
- PTR_LA ra, ret_from_irq
|
||||||
|
- PTR_LA v0, plat_irq_dispatch
|
||||||
|
- jr v0
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * SAVE_ALL ensures we are using a valid kernel stack for the thread.
|
||||||
|
+ * Check if we are already using the IRQ stack.
|
||||||
|
+ */
|
||||||
|
+ move s1, sp # Preserve the sp
|
||||||
|
+
|
||||||
|
+ /* Get IRQ stack for this CPU */
|
||||||
|
+ ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG
|
||||||
|
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
|
||||||
|
+ lui k1, %hi(irq_stack)
|
||||||
|
+#else
|
||||||
|
+ lui k1, %highest(irq_stack)
|
||||||
|
+ daddiu k1, %higher(irq_stack)
|
||||||
|
+ dsll k1, 16
|
||||||
|
+ daddiu k1, %hi(irq_stack)
|
||||||
|
+ dsll k1, 16
|
||||||
|
+#endif
|
||||||
|
+ LONG_SRL k0, SMP_CPUID_PTRSHIFT
|
||||||
|
+ LONG_ADDU k1, k0
|
||||||
|
+ LONG_L t0, %lo(irq_stack)(k1)
|
||||||
|
+
|
||||||
|
+ # Check if already on IRQ stack
|
||||||
|
+ PTR_LI t1, ~(_THREAD_SIZE-1)
|
||||||
|
+ and t1, t1, sp
|
||||||
|
+ beq t0, t1, 2f
|
||||||
|
+
|
||||||
|
+ /* Switch to IRQ stack */
|
||||||
|
+ li t1, _IRQ_STACK_SIZE
|
||||||
|
+ PTR_ADD sp, t0, t1
|
||||||
|
+
|
||||||
|
+2:
|
||||||
|
+ jal plat_irq_dispatch
|
||||||
|
+
|
||||||
|
+ /* Restore sp */
|
||||||
|
+ move sp, s1
|
||||||
|
+
|
||||||
|
+ j ret_from_irq
|
||||||
|
#ifdef CONFIG_CPU_MICROMIPS
|
||||||
|
nop
|
||||||
|
#endif
|
||||||
|
@@ -262,8 +297,44 @@ NESTED(except_vec_vi_handler, 0, sp)
|
||||||
|
|
||||||
|
LONG_L s0, TI_REGS($28)
|
||||||
|
LONG_S sp, TI_REGS($28)
|
||||||
|
- PTR_LA ra, ret_from_irq
|
||||||
|
- jr v0
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * SAVE_ALL ensures we are using a valid kernel stack for the thread.
|
||||||
|
+ * Check if we are already using the IRQ stack.
|
||||||
|
+ */
|
||||||
|
+ move s1, sp # Preserve the sp
|
||||||
|
+
|
||||||
|
+ /* Get IRQ stack for this CPU */
|
||||||
|
+ ASM_CPUID_MFC0 k0, ASM_SMP_CPUID_REG
|
||||||
|
+#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
|
||||||
|
+ lui k1, %hi(irq_stack)
|
||||||
|
+#else
|
||||||
|
+ lui k1, %highest(irq_stack)
|
||||||
|
+ daddiu k1, %higher(irq_stack)
|
||||||
|
+ dsll k1, 16
|
||||||
|
+ daddiu k1, %hi(irq_stack)
|
||||||
|
+ dsll k1, 16
|
||||||
|
+#endif
|
||||||
|
+ LONG_SRL k0, SMP_CPUID_PTRSHIFT
|
||||||
|
+ LONG_ADDU k1, k0
|
||||||
|
+ LONG_L t0, %lo(irq_stack)(k1)
|
||||||
|
+
|
||||||
|
+ # Check if already on IRQ stack
|
||||||
|
+ PTR_LI t1, ~(_THREAD_SIZE-1)
|
||||||
|
+ and t1, t1, sp
|
||||||
|
+ beq t0, t1, 2f
|
||||||
|
+
|
||||||
|
+ /* Switch to IRQ stack */
|
||||||
|
+ li t1, _IRQ_STACK_SIZE
|
||||||
|
+ PTR_ADD sp, t0, t1
|
||||||
|
+
|
||||||
|
+2:
|
||||||
|
+ jal plat_irq_dispatch
|
||||||
|
+
|
||||||
|
+ /* Restore sp */
|
||||||
|
+ move sp, s1
|
||||||
|
+
|
||||||
|
+ j ret_from_irq
|
||||||
|
END(except_vec_vi_handler)
|
||||||
|
|
||||||
|
/*
|
|
@ -0,0 +1,21 @@
|
||||||
|
From: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
Date: Mon, 19 Dec 2016 14:21:00 +0000
|
||||||
|
Subject: [PATCH] MIPS: Select HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||||
|
|
||||||
|
Since do_IRQ is now invoked on a separate IRQ stack, we select
|
||||||
|
HAVE_IRQ_EXIT_ON_IRQ_STACK so that softirq's may be invoked directly
|
||||||
|
from irq_exit(), rather than requiring do_softirq_own_stack.
|
||||||
|
|
||||||
|
Signed-off-by: Matt Redfearn <matt.redfearn@imgtec.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -9,6 +9,7 @@ config MIPS
|
||||||
|
select HAVE_CONTEXT_TRACKING
|
||||||
|
select HAVE_GENERIC_DMA_COHERENT
|
||||||
|
select HAVE_IDE
|
||||||
|
+ select HAVE_IRQ_EXIT_ON_IRQ_STACK
|
||||||
|
select HAVE_OPROFILE
|
||||||
|
select HAVE_PERF_EVENTS
|
||||||
|
select PERF_USE_VMALLOC
|
|
@ -0,0 +1,24 @@
|
||||||
|
From cd4b1e34655d46950c065d9284b596cd8d7b28cd Mon Sep 17 00:00:00 2001
|
||||||
|
From: John Youn <johnyoun@synopsys.com>
|
||||||
|
Date: Thu, 3 Nov 2016 17:55:45 -0700
|
||||||
|
Subject: [PATCH] usb: dwc2: Remove unnecessary kfree
|
||||||
|
|
||||||
|
This shouldn't be freed by the HCD as it is owned by the core and
|
||||||
|
allocated with devm_kzalloc.
|
||||||
|
|
||||||
|
Signed-off-by: John Youn <johnyoun@synopsys.com>
|
||||||
|
Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
|
||||||
|
---
|
||||||
|
drivers/usb/dwc2/hcd.c | 1 -
|
||||||
|
1 file changed, 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/drivers/usb/dwc2/hcd.c
|
||||||
|
+++ b/drivers/usb/dwc2/hcd.c
|
||||||
|
@@ -5184,7 +5184,6 @@ error3:
|
||||||
|
error2:
|
||||||
|
usb_put_hcd(hcd);
|
||||||
|
error1:
|
||||||
|
- kfree(hsotg->core_params);
|
||||||
|
|
||||||
|
#ifdef CONFIG_USB_DWC2_TRACK_MISSED_SOFS
|
||||||
|
kfree(hsotg->last_frame_num_array);
|
|
@ -0,0 +1,40 @@
|
||||||
|
From bd5d21310133921021d78995ad6346f908483124 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Sun, 20 Nov 2016 16:09:30 +0100
|
||||||
|
Subject: [PATCH] mtd: bcm47xxpart: fix parsing first block after aligned TRX
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
After parsing TRX we should skip to the first block placed behind it.
|
||||||
|
Our code was working only with TRX with length not aligned to the
|
||||||
|
blocksize. In other cases (length aligned) it was missing the block
|
||||||
|
places right after TRX.
|
||||||
|
|
||||||
|
This fixes calculation and simplifies the comment.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Signed-off-by: Brian Norris <computersforpeace@gmail.com>
|
||||||
|
---
|
||||||
|
drivers/mtd/bcm47xxpart.c | 10 ++++------
|
||||||
|
1 file changed, 4 insertions(+), 6 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/mtd/bcm47xxpart.c
|
||||||
|
+++ b/drivers/mtd/bcm47xxpart.c
|
||||||
|
@@ -229,12 +229,10 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
|
||||||
|
last_trx_part = curr_part - 1;
|
||||||
|
|
||||||
|
- /*
|
||||||
|
- * We have whole TRX scanned, skip to the next part. Use
|
||||||
|
- * roundown (not roundup), as the loop will increase
|
||||||
|
- * offset in next step.
|
||||||
|
- */
|
||||||
|
- offset = rounddown(offset + trx->length, blocksize);
|
||||||
|
+ /* Jump to the end of TRX */
|
||||||
|
+ offset = roundup(offset + trx->length, blocksize);
|
||||||
|
+ /* Next loop iteration will increase the offset */
|
||||||
|
+ offset -= blocksize;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
--- a/drivers/bcma/main.c
|
||||||
|
+++ b/drivers/bcma/main.c
|
||||||
|
@@ -136,17 +136,17 @@ static bool bcma_is_core_needed_early(u1
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static struct device_node *bcma_of_find_child_device(struct platform_device *parent,
|
||||||
|
+static struct device_node *bcma_of_find_child_device(struct device *parent,
|
||||||
|
struct bcma_device *core)
|
||||||
|
{
|
||||||
|
struct device_node *node;
|
||||||
|
u64 size;
|
||||||
|
const __be32 *reg;
|
||||||
|
|
||||||
|
- if (!parent || !parent->dev.of_node)
|
||||||
|
+ if (!parent->of_node)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
- for_each_child_of_node(parent->dev.of_node, node) {
|
||||||
|
+ for_each_child_of_node(parent->of_node, node) {
|
||||||
|
reg = of_get_address(node, 0, &size, NULL);
|
||||||
|
if (!reg)
|
||||||
|
continue;
|
||||||
|
@@ -156,7 +156,7 @@ static struct device_node *bcma_of_find_
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int bcma_of_irq_parse(struct platform_device *parent,
|
||||||
|
+static int bcma_of_irq_parse(struct device *parent,
|
||||||
|
struct bcma_device *core,
|
||||||
|
struct of_phandle_args *out_irq, int num)
|
||||||
|
{
|
||||||
|
@@ -169,7 +169,7 @@ static int bcma_of_irq_parse(struct plat
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
- out_irq->np = parent->dev.of_node;
|
||||||
|
+ out_irq->np = parent->of_node;
|
||||||
|
out_irq->args_count = 1;
|
||||||
|
out_irq->args[0] = num;
|
||||||
|
|
||||||
|
@@ -177,13 +177,13 @@ static int bcma_of_irq_parse(struct plat
|
||||||
|
return of_irq_parse_raw(laddr, out_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static unsigned int bcma_of_get_irq(struct platform_device *parent,
|
||||||
|
+static unsigned int bcma_of_get_irq(struct device *parent,
|
||||||
|
struct bcma_device *core, int num)
|
||||||
|
{
|
||||||
|
struct of_phandle_args out_irq;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
- if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent || !parent->dev.of_node)
|
||||||
|
+ if (!IS_ENABLED(CONFIG_OF_IRQ) || !parent->of_node)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
ret = bcma_of_irq_parse(parent, core, &out_irq, num);
|
||||||
|
@@ -196,7 +196,7 @@ static unsigned int bcma_of_get_irq(stru
|
||||||
|
return irq_create_of_mapping(&out_irq);
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void bcma_of_fill_device(struct platform_device *parent,
|
||||||
|
+static void bcma_of_fill_device(struct device *parent,
|
||||||
|
struct bcma_device *core)
|
||||||
|
{
|
||||||
|
struct device_node *node;
|
||||||
|
@@ -227,7 +227,7 @@ unsigned int bcma_core_irq(struct bcma_d
|
||||||
|
return mips_irq <= 4 ? mips_irq + 2 : 0;
|
||||||
|
}
|
||||||
|
if (bus->host_pdev)
|
||||||
|
- return bcma_of_get_irq(bus->host_pdev, core, num);
|
||||||
|
+ return bcma_of_get_irq(&bus->host_pdev->dev, core, num);
|
||||||
|
return 0;
|
||||||
|
case BCMA_HOSTTYPE_SDIO:
|
||||||
|
return 0;
|
||||||
|
@@ -253,7 +253,8 @@ void bcma_prepare_core(struct bcma_bus *
|
||||||
|
if (IS_ENABLED(CONFIG_OF) && bus->host_pdev) {
|
||||||
|
core->dma_dev = &bus->host_pdev->dev;
|
||||||
|
core->dev.parent = &bus->host_pdev->dev;
|
||||||
|
- bcma_of_fill_device(bus->host_pdev, core);
|
||||||
|
+ if (core->dev.parent)
|
||||||
|
+ bcma_of_fill_device(core->dev.parent, core);
|
||||||
|
} else {
|
||||||
|
core->dev.dma_mask = &core->dev.coherent_dma_mask;
|
||||||
|
core->dma_dev = &core->dev;
|
||||||
|
@@ -633,8 +634,11 @@ static int bcma_device_probe(struct devi
|
||||||
|
drv);
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
+ get_device(dev);
|
||||||
|
if (adrv->probe)
|
||||||
|
err = adrv->probe(core);
|
||||||
|
+ if (err)
|
||||||
|
+ put_device(dev);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
@@ -647,6 +651,7 @@ static int bcma_device_remove(struct dev
|
||||||
|
|
||||||
|
if (adrv->remove)
|
||||||
|
adrv->remove(core);
|
||||||
|
+ put_device(dev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,139 @@
|
||||||
|
From 34a5102c3235c470a6c77fba16cb971964d9c136 Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 31 Jan 2017 19:37:54 +0100
|
||||||
|
Subject: [PATCH 1/3] net: bgmac: allocate struct bgmac just once & don't copy
|
||||||
|
it
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
So far were were allocating struct bgmac in 3 places: platform code,
|
||||||
|
bcma code and shared bgmac_enet_probe function. The reason for this was
|
||||||
|
bgmac_enet_probe:
|
||||||
|
1) Requiring early-filled struct bgmac
|
||||||
|
2) Calling alloc_etherdev on its own in order to use netdev_priv later
|
||||||
|
|
||||||
|
This solution got few drawbacks:
|
||||||
|
1) Was duplicating allocating code
|
||||||
|
2) Required copying early-filled struct
|
||||||
|
3) Resulted in platform/bcma code having access only to unused struct
|
||||||
|
|
||||||
|
Solve this situation by simply extracting some probe code into the new
|
||||||
|
bgmac_alloc function.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/ethernet/broadcom/bgmac-bcma.c | 4 +---
|
||||||
|
drivers/net/ethernet/broadcom/bgmac-platform.c | 2 +-
|
||||||
|
drivers/net/ethernet/broadcom/bgmac.c | 25 +++++++++++++++++--------
|
||||||
|
drivers/net/ethernet/broadcom/bgmac.h | 3 ++-
|
||||||
|
4 files changed, 21 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||||
|
@@ -99,12 +99,11 @@ static int bgmac_probe(struct bcma_devic
|
||||||
|
u8 *mac;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- bgmac = kzalloc(sizeof(*bgmac), GFP_KERNEL);
|
||||||
|
+ bgmac = bgmac_alloc(&core->dev);
|
||||||
|
if (!bgmac)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
bgmac->bcma.core = core;
|
||||||
|
- bgmac->dev = &core->dev;
|
||||||
|
bgmac->dma_dev = core->dma_dev;
|
||||||
|
bgmac->irq = core->irq;
|
||||||
|
|
||||||
|
@@ -285,7 +284,6 @@ static int bgmac_probe(struct bcma_devic
|
||||||
|
err1:
|
||||||
|
bcma_mdio_mii_unregister(bgmac->mii_bus);
|
||||||
|
err:
|
||||||
|
- kfree(bgmac);
|
||||||
|
bcma_set_drvdata(core, NULL);
|
||||||
|
|
||||||
|
return err;
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac-platform.c
|
||||||
|
@@ -93,7 +93,7 @@ static int bgmac_probe(struct platform_d
|
||||||
|
struct resource *regs;
|
||||||
|
const u8 *mac_addr;
|
||||||
|
|
||||||
|
- bgmac = devm_kzalloc(&pdev->dev, sizeof(*bgmac), GFP_KERNEL);
|
||||||
|
+ bgmac = bgmac_alloc(&pdev->dev);
|
||||||
|
if (!bgmac)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac.c
|
||||||
|
@@ -1459,22 +1459,32 @@ static int bgmac_phy_connect(struct bgma
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
-int bgmac_enet_probe(struct bgmac *info)
|
||||||
|
+struct bgmac *bgmac_alloc(struct device *dev)
|
||||||
|
{
|
||||||
|
struct net_device *net_dev;
|
||||||
|
struct bgmac *bgmac;
|
||||||
|
- int err;
|
||||||
|
|
||||||
|
/* Allocation and references */
|
||||||
|
- net_dev = alloc_etherdev(sizeof(*bgmac));
|
||||||
|
+ net_dev = devm_alloc_etherdev(dev, sizeof(*bgmac));
|
||||||
|
if (!net_dev)
|
||||||
|
- return -ENOMEM;
|
||||||
|
+ return NULL;
|
||||||
|
|
||||||
|
net_dev->netdev_ops = &bgmac_netdev_ops;
|
||||||
|
net_dev->ethtool_ops = &bgmac_ethtool_ops;
|
||||||
|
+
|
||||||
|
bgmac = netdev_priv(net_dev);
|
||||||
|
- memcpy(bgmac, info, sizeof(*bgmac));
|
||||||
|
+ bgmac->dev = dev;
|
||||||
|
bgmac->net_dev = net_dev;
|
||||||
|
+
|
||||||
|
+ return bgmac;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(bgmac_alloc);
|
||||||
|
+
|
||||||
|
+int bgmac_enet_probe(struct bgmac *bgmac)
|
||||||
|
+{
|
||||||
|
+ struct net_device *net_dev = bgmac->net_dev;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
net_dev->irq = bgmac->irq;
|
||||||
|
SET_NETDEV_DEV(net_dev, bgmac->dev);
|
||||||
|
|
||||||
|
@@ -1501,7 +1511,7 @@ int bgmac_enet_probe(struct bgmac *info)
|
||||||
|
err = bgmac_dma_alloc(bgmac);
|
||||||
|
if (err) {
|
||||||
|
dev_err(bgmac->dev, "Unable to alloc memory for DMA\n");
|
||||||
|
- goto err_netdev_free;
|
||||||
|
+ goto err_out;
|
||||||
|
}
|
||||||
|
|
||||||
|
bgmac->int_mask = BGMAC_IS_ERRMASK | BGMAC_IS_RX | BGMAC_IS_TX_MASK;
|
||||||
|
@@ -1537,8 +1547,7 @@ err_phy_disconnect:
|
||||||
|
phy_disconnect(net_dev->phydev);
|
||||||
|
err_dma_free:
|
||||||
|
bgmac_dma_free(bgmac);
|
||||||
|
-err_netdev_free:
|
||||||
|
- free_netdev(net_dev);
|
||||||
|
+err_out:
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||||
|
@@ -515,7 +515,8 @@ struct bgmac {
|
||||||
|
u32 set);
|
||||||
|
};
|
||||||
|
|
||||||
|
-int bgmac_enet_probe(struct bgmac *info);
|
||||||
|
+struct bgmac *bgmac_alloc(struct device *dev);
|
||||||
|
+int bgmac_enet_probe(struct bgmac *bgmac);
|
||||||
|
void bgmac_enet_remove(struct bgmac *bgmac);
|
||||||
|
|
||||||
|
struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
|
|
@ -0,0 +1,261 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 31 Jan 2017 19:37:55 +0100
|
||||||
|
Subject: [PATCH] net: bgmac: drop struct bcma_mdio we don't need anymore
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Adding struct bcma_mdio was a workaround for bcma code not having access
|
||||||
|
to the struct bgmac used in the core code. Now we don't duplicate this
|
||||||
|
struct we can just use it internally in bcma code.
|
||||||
|
|
||||||
|
This simplifies code & allows access to all bgmac driver details from
|
||||||
|
all places in bcma code.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma.c
|
||||||
|
@@ -159,7 +159,7 @@ static int bgmac_probe(struct bcma_devic
|
||||||
|
|
||||||
|
if (!bgmac_is_bcm4707_family(core) &&
|
||||||
|
!(ci->id == BCMA_CHIP_ID_BCM53573 && core->core_unit == 1)) {
|
||||||
|
- mii_bus = bcma_mdio_mii_register(core, bgmac->phyaddr);
|
||||||
|
+ mii_bus = bcma_mdio_mii_register(bgmac);
|
||||||
|
if (IS_ERR(mii_bus)) {
|
||||||
|
err = PTR_ERR(mii_bus);
|
||||||
|
goto err;
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||||
|
@@ -12,11 +12,6 @@
|
||||||
|
#include <linux/brcmphy.h>
|
||||||
|
#include "bgmac.h"
|
||||||
|
|
||||||
|
-struct bcma_mdio {
|
||||||
|
- struct bcma_device *core;
|
||||||
|
- u8 phyaddr;
|
||||||
|
-};
|
||||||
|
-
|
||||||
|
static bool bcma_mdio_wait_value(struct bcma_device *core, u16 reg, u32 mask,
|
||||||
|
u32 value, int timeout)
|
||||||
|
{
|
||||||
|
@@ -37,7 +32,7 @@ static bool bcma_mdio_wait_value(struct
|
||||||
|
* PHY ops
|
||||||
|
**************************************************/
|
||||||
|
|
||||||
|
-static u16 bcma_mdio_phy_read(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg)
|
||||||
|
+static u16 bcma_mdio_phy_read(struct bgmac *bgmac, u8 phyaddr, u8 reg)
|
||||||
|
{
|
||||||
|
struct bcma_device *core;
|
||||||
|
u16 phy_access_addr;
|
||||||
|
@@ -56,12 +51,12 @@ static u16 bcma_mdio_phy_read(struct bcm
|
||||||
|
BUILD_BUG_ON(BGMAC_PC_MCT_SHIFT != BCMA_GMAC_CMN_PC_MCT_SHIFT);
|
||||||
|
BUILD_BUG_ON(BGMAC_PC_MTE != BCMA_GMAC_CMN_PC_MTE);
|
||||||
|
|
||||||
|
- if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||||
|
- core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||||
|
+ if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||||
|
+ core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
|
||||||
|
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||||
|
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||||
|
} else {
|
||||||
|
- core = bcma_mdio->core;
|
||||||
|
+ core = bgmac->bcma.core;
|
||||||
|
phy_access_addr = BGMAC_PHY_ACCESS;
|
||||||
|
phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||||
|
}
|
||||||
|
@@ -87,7 +82,7 @@ static u16 bcma_mdio_phy_read(struct bcm
|
||||||
|
}
|
||||||
|
|
||||||
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphywr */
|
||||||
|
-static int bcma_mdio_phy_write(struct bcma_mdio *bcma_mdio, u8 phyaddr, u8 reg,
|
||||||
|
+static int bcma_mdio_phy_write(struct bgmac *bgmac, u8 phyaddr, u8 reg,
|
||||||
|
u16 value)
|
||||||
|
{
|
||||||
|
struct bcma_device *core;
|
||||||
|
@@ -95,12 +90,12 @@ static int bcma_mdio_phy_write(struct bc
|
||||||
|
u16 phy_ctl_addr;
|
||||||
|
u32 tmp;
|
||||||
|
|
||||||
|
- if (bcma_mdio->core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||||
|
- core = bcma_mdio->core->bus->drv_gmac_cmn.core;
|
||||||
|
+ if (bgmac->bcma.core->id.id == BCMA_CORE_4706_MAC_GBIT) {
|
||||||
|
+ core = bgmac->bcma.core->bus->drv_gmac_cmn.core;
|
||||||
|
phy_access_addr = BCMA_GMAC_CMN_PHY_ACCESS;
|
||||||
|
phy_ctl_addr = BCMA_GMAC_CMN_PHY_CTL;
|
||||||
|
} else {
|
||||||
|
- core = bcma_mdio->core;
|
||||||
|
+ core = bgmac->bcma.core;
|
||||||
|
phy_access_addr = BGMAC_PHY_ACCESS;
|
||||||
|
phy_ctl_addr = BGMAC_PHY_CNTL;
|
||||||
|
}
|
||||||
|
@@ -110,8 +105,8 @@ static int bcma_mdio_phy_write(struct bc
|
||||||
|
tmp |= phyaddr;
|
||||||
|
bcma_write32(core, phy_ctl_addr, tmp);
|
||||||
|
|
||||||
|
- bcma_write32(bcma_mdio->core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||||
|
- if (bcma_read32(bcma_mdio->core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||||
|
+ bcma_write32(bgmac->bcma.core, BGMAC_INT_STATUS, BGMAC_IS_MDIO);
|
||||||
|
+ if (bcma_read32(bgmac->bcma.core, BGMAC_INT_STATUS) & BGMAC_IS_MDIO)
|
||||||
|
dev_warn(&core->dev, "Error setting MDIO int\n");
|
||||||
|
|
||||||
|
tmp = BGMAC_PA_START;
|
||||||
|
@@ -132,39 +127,39 @@ static int bcma_mdio_phy_write(struct bc
|
||||||
|
}
|
||||||
|
|
||||||
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyinit */
|
||||||
|
-static void bcma_mdio_phy_init(struct bcma_mdio *bcma_mdio)
|
||||||
|
+static void bcma_mdio_phy_init(struct bgmac *bgmac)
|
||||||
|
{
|
||||||
|
- struct bcma_chipinfo *ci = &bcma_mdio->core->bus->chipinfo;
|
||||||
|
+ struct bcma_chipinfo *ci = &bgmac->bcma.core->bus->chipinfo;
|
||||||
|
u8 i;
|
||||||
|
|
||||||
|
if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x008b);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x15, 0x0100);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x12, 0x2aaa);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x008b);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x15, 0x0100);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x12, 0x2aaa);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||||
|
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||||
|
(ci->id == BCMA_CHIP_ID_BCM53572 && ci->pkg != 9)) {
|
||||||
|
- struct bcma_drv_cc *cc = &bcma_mdio->core->bus->drv_cc;
|
||||||
|
+ struct bcma_drv_cc *cc = &bgmac->bcma.core->bus->drv_cc;
|
||||||
|
|
||||||
|
bcma_chipco_chipctl_maskset(cc, 2, ~0xc0000000, 0);
|
||||||
|
bcma_chipco_chipctl_maskset(cc, 4, ~0x80000000, 0);
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5284);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x0010);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000f);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x5296);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x1073);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9073);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x16, 0x52b6);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x17, 0x9273);
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, i, 0x1f, 0x000b);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x5284);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x0010);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000f);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x5296);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x1073);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x9073);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x16, 0x52b6);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x17, 0x9273);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -172,17 +167,17 @@ static void bcma_mdio_phy_init(struct bc
|
||||||
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
||||||
|
static int bcma_mdio_phy_reset(struct mii_bus *bus)
|
||||||
|
{
|
||||||
|
- struct bcma_mdio *bcma_mdio = bus->priv;
|
||||||
|
- u8 phyaddr = bcma_mdio->phyaddr;
|
||||||
|
+ struct bgmac *bgmac = bus->priv;
|
||||||
|
+ u8 phyaddr = bgmac->phyaddr;
|
||||||
|
|
||||||
|
- if (bcma_mdio->phyaddr == BGMAC_PHY_NOREGS)
|
||||||
|
+ if (phyaddr == BGMAC_PHY_NOREGS)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
- bcma_mdio_phy_write(bcma_mdio, phyaddr, MII_BMCR, BMCR_RESET);
|
||||||
|
+ bcma_mdio_phy_write(bgmac, phyaddr, MII_BMCR, BMCR_RESET);
|
||||||
|
udelay(100);
|
||||||
|
- if (bcma_mdio_phy_read(bcma_mdio, phyaddr, MII_BMCR) & BMCR_RESET)
|
||||||
|
- dev_err(&bcma_mdio->core->dev, "PHY reset failed\n");
|
||||||
|
- bcma_mdio_phy_init(bcma_mdio);
|
||||||
|
+ if (bcma_mdio_phy_read(bgmac, phyaddr, MII_BMCR) & BMCR_RESET)
|
||||||
|
+ dev_err(bgmac->dev, "PHY reset failed\n");
|
||||||
|
+ bcma_mdio_phy_init(bgmac);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -202,16 +197,12 @@ static int bcma_mdio_mii_write(struct mi
|
||||||
|
return bcma_mdio_phy_write(bus->priv, mii_id, regnum, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
-struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr)
|
||||||
|
+struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac)
|
||||||
|
{
|
||||||
|
- struct bcma_mdio *bcma_mdio;
|
||||||
|
+ struct bcma_device *core = bgmac->bcma.core;
|
||||||
|
struct mii_bus *mii_bus;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
- bcma_mdio = kzalloc(sizeof(*bcma_mdio), GFP_KERNEL);
|
||||||
|
- if (!bcma_mdio)
|
||||||
|
- return ERR_PTR(-ENOMEM);
|
||||||
|
-
|
||||||
|
mii_bus = mdiobus_alloc();
|
||||||
|
if (!mii_bus) {
|
||||||
|
err = -ENOMEM;
|
||||||
|
@@ -221,15 +212,12 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||||
|
mii_bus->name = "bcma_mdio mii bus";
|
||||||
|
sprintf(mii_bus->id, "%s-%d-%d", "bcma_mdio", core->bus->num,
|
||||||
|
core->core_unit);
|
||||||
|
- mii_bus->priv = bcma_mdio;
|
||||||
|
+ mii_bus->priv = bgmac;
|
||||||
|
mii_bus->read = bcma_mdio_mii_read;
|
||||||
|
mii_bus->write = bcma_mdio_mii_write;
|
||||||
|
mii_bus->reset = bcma_mdio_phy_reset;
|
||||||
|
mii_bus->parent = &core->dev;
|
||||||
|
- mii_bus->phy_mask = ~(1 << phyaddr);
|
||||||
|
-
|
||||||
|
- bcma_mdio->core = core;
|
||||||
|
- bcma_mdio->phyaddr = phyaddr;
|
||||||
|
+ mii_bus->phy_mask = ~(1 << bgmac->phyaddr);
|
||||||
|
|
||||||
|
err = mdiobus_register(mii_bus);
|
||||||
|
if (err) {
|
||||||
|
@@ -242,23 +230,17 @@ struct mii_bus *bcma_mdio_mii_register(s
|
||||||
|
err_free_bus:
|
||||||
|
mdiobus_free(mii_bus);
|
||||||
|
err:
|
||||||
|
- kfree(bcma_mdio);
|
||||||
|
return ERR_PTR(err);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bcma_mdio_mii_register);
|
||||||
|
|
||||||
|
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus)
|
||||||
|
{
|
||||||
|
- struct bcma_mdio *bcma_mdio;
|
||||||
|
-
|
||||||
|
if (!mii_bus)
|
||||||
|
return;
|
||||||
|
|
||||||
|
- bcma_mdio = mii_bus->priv;
|
||||||
|
-
|
||||||
|
mdiobus_unregister(mii_bus);
|
||||||
|
mdiobus_free(mii_bus);
|
||||||
|
- kfree(bcma_mdio);
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bcma_mdio_mii_unregister);
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac.h
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac.h
|
||||||
|
@@ -519,7 +519,7 @@ struct bgmac *bgmac_alloc(struct device
|
||||||
|
int bgmac_enet_probe(struct bgmac *bgmac);
|
||||||
|
void bgmac_enet_remove(struct bgmac *bgmac);
|
||||||
|
|
||||||
|
-struct mii_bus *bcma_mdio_mii_register(struct bcma_device *core, u8 phyaddr);
|
||||||
|
+struct mii_bus *bcma_mdio_mii_register(struct bgmac *bgmac);
|
||||||
|
void bcma_mdio_mii_unregister(struct mii_bus *mii_bus);
|
||||||
|
|
||||||
|
static inline u32 bgmac_read(struct bgmac *bgmac, u16 offset)
|
|
@ -0,0 +1,53 @@
|
||||||
|
From 8e6f31baba7e2c13ab7e954fe6179420a7545a8b Mon Sep 17 00:00:00 2001
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 31 Jan 2017 19:37:56 +0100
|
||||||
|
Subject: [PATCH 3/3] net: bgmac: use PHY subsystem for initializing PHY
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
This adds support for using bgmac with PHYs supported by standalone PHY
|
||||||
|
drivers. Having any PHY initialization in bgmac is hacky and shouldn't
|
||||||
|
be extended but rather removed if anyone has hardware to test it.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c | 10 ++++++++++
|
||||||
|
1 file changed, 10 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||||
|
+++ b/drivers/net/ethernet/broadcom/bgmac-bcma-mdio.c
|
||||||
|
@@ -132,6 +132,10 @@ static void bcma_mdio_phy_init(struct bg
|
||||||
|
struct bcma_chipinfo *ci = &bgmac->bcma.core->bus->chipinfo;
|
||||||
|
u8 i;
|
||||||
|
|
||||||
|
+ /* For some legacy hardware we do chipset-based PHY initialization here
|
||||||
|
+ * without even detecting PHY ID. It's hacky and should be cleaned as
|
||||||
|
+ * soon as someone can test it.
|
||||||
|
+ */
|
||||||
|
if (ci->id == BCMA_CHIP_ID_BCM5356) {
|
||||||
|
for (i = 0; i < 5; i++) {
|
||||||
|
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x008b);
|
||||||
|
@@ -140,6 +144,7 @@ static void bcma_mdio_phy_init(struct bg
|
||||||
|
bcma_mdio_phy_write(bgmac, i, 0x12, 0x2aaa);
|
||||||
|
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||||
|
}
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
if ((ci->id == BCMA_CHIP_ID_BCM5357 && ci->pkg != 10) ||
|
||||||
|
(ci->id == BCMA_CHIP_ID_BCM4749 && ci->pkg != 10) ||
|
||||||
|
@@ -161,7 +166,12 @@ static void bcma_mdio_phy_init(struct bg
|
||||||
|
bcma_mdio_phy_write(bgmac, i, 0x17, 0x9273);
|
||||||
|
bcma_mdio_phy_write(bgmac, i, 0x1f, 0x000b);
|
||||||
|
}
|
||||||
|
+ return;
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /* For all other hw do initialization using PHY subsystem. */
|
||||||
|
+ if (bgmac->net_dev && bgmac->net_dev->phydev)
|
||||||
|
+ phy_init_hw(bgmac->net_dev->phydev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* http://bcm-v4.sipsolutions.net/mac-gbit/gmac/chipphyreset */
|
|
@ -0,0 +1,34 @@
|
||||||
|
From: Xo Wang <xow@google.com>
|
||||||
|
Date: Fri, 21 Oct 2016 10:20:12 -0700
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Update Auxiliary Control Register macros
|
||||||
|
|
||||||
|
Add the RXD-to-RXC skew (delay) time bit in the Miscellaneous Control
|
||||||
|
shadow register and a mask for the shadow selector field.
|
||||||
|
|
||||||
|
Remove a re-definition of MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL.
|
||||||
|
|
||||||
|
Signed-off-by: Xo Wang <xow@google.com>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Reviewed-by: Joel Stanley <joel@jms.id.au>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -101,6 +101,7 @@
|
||||||
|
* AUXILIARY CONTROL SHADOW ACCESS REGISTERS. (PHY REG 0x18)
|
||||||
|
*/
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
|
||||||
|
+#define MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW 0x0100
|
||||||
|
#define MII_BCM54XX_AUXCTL_ACTL_TX_6DB 0x0400
|
||||||
|
#define MII_BCM54XX_AUXCTL_ACTL_SMDSP_ENA 0x0800
|
||||||
|
|
||||||
|
@@ -109,7 +110,7 @@
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||||
|
|
||||||
|
-#define MII_BCM54XX_AUXCTL_SHDWSEL_AUXCTL 0x0000
|
||||||
|
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Broadcom LED source encodings. These are used in BCM5461, BCM5481,
|
|
@ -0,0 +1,94 @@
|
||||||
|
From: Xo Wang <xow@google.com>
|
||||||
|
Date: Fri, 21 Oct 2016 10:20:13 -0700
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Add support for BCM54612E
|
||||||
|
|
||||||
|
This PHY has internal delays enabled after reset. This clears the
|
||||||
|
internal delay enables unless the interface specifically requests them.
|
||||||
|
|
||||||
|
Signed-off-by: Xo Wang <xow@google.com>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Reviewed-by: Joel Stanley <joel@jms.id.au>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -337,6 +337,41 @@ static int bcm5481_config_aneg(struct ph
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int bcm54612e_config_aneg(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int ret;
|
||||||
|
+
|
||||||
|
+ /* First, auto-negotiate. */
|
||||||
|
+ ret = genphy_config_aneg(phydev);
|
||||||
|
+
|
||||||
|
+ /* Clear TX internal delay unless requested. */
|
||||||
|
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||||
|
+ /* Disable TXD to GTXCLK clock delay (default set) */
|
||||||
|
+ /* Bit 9 is the only field in shadow register 00011 */
|
||||||
|
+ bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Clear RX internal delay unless requested. */
|
||||||
|
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||||
|
+ u16 reg;
|
||||||
|
+
|
||||||
|
+ /* Errata: reads require filling in the write selector field */
|
||||||
|
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
+ MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC);
|
||||||
|
+ reg = phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||||
|
+ /* Disable RXD to RXC delay (default set) */
|
||||||
|
+ reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
|
||||||
|
+ /* Clear shadow selector field */
|
||||||
|
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||||
|
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
+ MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
@@ -485,6 +520,18 @@ static struct phy_driver broadcom_driver
|
||||||
|
.ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
.config_intr = bcm_phy_config_intr,
|
||||||
|
}, {
|
||||||
|
+ .phy_id = PHY_ID_BCM54612E,
|
||||||
|
+ .phy_id_mask = 0xfffffff0,
|
||||||
|
+ .name = "Broadcom BCM54612E",
|
||||||
|
+ .features = PHY_GBIT_FEATURES |
|
||||||
|
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||||
|
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||||
|
+ .config_init = bcm54xx_config_init,
|
||||||
|
+ .config_aneg = bcm54612e_config_aneg,
|
||||||
|
+ .read_status = genphy_read_status,
|
||||||
|
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
+ .config_intr = bcm_phy_config_intr,
|
||||||
|
+}, {
|
||||||
|
.phy_id = PHY_ID_BCM54616S,
|
||||||
|
.phy_id_mask = 0xfffffff0,
|
||||||
|
.name = "Broadcom BCM54616S",
|
||||||
|
@@ -600,6 +647,7 @@ static struct mdio_device_id __maybe_unu
|
||||||
|
{ PHY_ID_BCM5411, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5421, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5461, 0xfffffff0 },
|
||||||
|
+ { PHY_ID_BCM54612E, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5464, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5481, 0xfffffff0 },
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
#define PHY_ID_BCM5421 0x002060e0
|
||||||
|
#define PHY_ID_BCM5464 0x002060b0
|
||||||
|
#define PHY_ID_BCM5461 0x002060c0
|
||||||
|
+#define PHY_ID_BCM54612E 0x03625e60
|
||||||
|
#define PHY_ID_BCM54616S 0x03625d10
|
||||||
|
#define PHY_ID_BCM57780 0x03625d90
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
From: Jon Mason <jon.mason@broadcom.com>
|
||||||
|
Date: Fri, 4 Nov 2016 01:10:56 -0400
|
||||||
|
Subject: [PATCH] net: phy: broadcom: add bcm54xx_auxctl_read
|
||||||
|
|
||||||
|
Add a helper function to read the AUXCTL register for the BCM54xx. This
|
||||||
|
mirrors the bcm54xx_auxctl_write function already present in the code.
|
||||||
|
|
||||||
|
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -30,6 +30,16 @@ MODULE_DESCRIPTION("Broadcom PHY driver"
|
||||||
|
MODULE_AUTHOR("Maciej W. Rozycki");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
+static int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
|
||||||
|
+{
|
||||||
|
+ /* The register must be written to both the Shadow Register Select and
|
||||||
|
+ * the Shadow Read Register Selector
|
||||||
|
+ */
|
||||||
|
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum |
|
||||||
|
+ regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
|
||||||
|
+ return phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
|
||||||
|
{
|
||||||
|
return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -110,6 +110,7 @@
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||||
|
+#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||||
|
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
|
||||||
|
|
|
@ -0,0 +1,176 @@
|
||||||
|
From: Jon Mason <jon.mason@broadcom.com>
|
||||||
|
Date: Fri, 4 Nov 2016 01:10:58 -0400
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Add BCM54810 PHY entry
|
||||||
|
|
||||||
|
The BCM54810 PHY requires some semi-unique configuration, which results
|
||||||
|
in some additional configuration in addition to the standard config.
|
||||||
|
Also, some users of the BCM54810 require the PHY lanes to be swapped.
|
||||||
|
Since there is no way to detect this, add a device tree query to see if
|
||||||
|
it is applicable.
|
||||||
|
|
||||||
|
Inspired-by: Vikas Soni <vsoni@broadcom.com>
|
||||||
|
Signed-off-by: Jon Mason <jon.mason@broadcom.com>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -18,7 +18,7 @@
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
|
#include <linux/brcmphy.h>
|
||||||
|
-
|
||||||
|
+#include <linux/of.h>
|
||||||
|
|
||||||
|
#define BRCM_PHY_MODEL(phydev) \
|
||||||
|
((phydev)->drv->phy_id & (phydev)->drv->phy_id_mask)
|
||||||
|
@@ -45,6 +45,34 @@ static int bcm54xx_auxctl_write(struct p
|
||||||
|
return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int bcm54810_config(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int rc, val;
|
||||||
|
+
|
||||||
|
+ val = bcm_phy_read_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL);
|
||||||
|
+ val &= ~BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN;
|
||||||
|
+ rc = bcm_phy_write_exp(phydev, BCM54810_EXP_BROADREACH_LRE_MISC_CTL,
|
||||||
|
+ val);
|
||||||
|
+ if (rc < 0)
|
||||||
|
+ return rc;
|
||||||
|
+
|
||||||
|
+ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||||
|
+ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||||
|
+ val |= MII_BCM54XX_AUXCTL_MISC_WREN;
|
||||||
|
+ rc = bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
+ val);
|
||||||
|
+ if (rc < 0)
|
||||||
|
+ return rc;
|
||||||
|
+
|
||||||
|
+ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
|
||||||
|
+ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
|
||||||
|
+ rc = bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
|
||||||
|
+ if (rc < 0)
|
||||||
|
+ return rc;
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
/* Needs SMDSP clock enabled via bcm54xx_phydsp_config() */
|
||||||
|
static int bcm50610_a0_workaround(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
@@ -217,6 +245,12 @@ static int bcm54xx_config_init(struct ph
|
||||||
|
(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
|
||||||
|
bcm54xx_adjust_rxrefclk(phydev);
|
||||||
|
|
||||||
|
+ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||||
|
+ err = bcm54810_config(phydev);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
bcm54xx_phydsp_config(phydev);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
@@ -314,6 +348,7 @@ static int bcm5482_read_status(struct ph
|
||||||
|
|
||||||
|
static int bcm5481_config_aneg(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
+ struct device_node *np = phydev->mdio.dev.of_node;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
/* Aneg firsly. */
|
||||||
|
@@ -344,6 +379,14 @@ static int bcm5481_config_aneg(struct ph
|
||||||
|
phy_write(phydev, 0x18, reg);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (of_property_read_bool(np, "enet-phy-lane-swap")) {
|
||||||
|
+ /* Lane Swap - Undocumented register...magic! */
|
||||||
|
+ ret = bcm_phy_write_exp(phydev, MII_BCM54XX_EXP_SEL_ER + 0x9,
|
||||||
|
+ 0x11B);
|
||||||
|
+ if (ret < 0)
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -578,6 +621,18 @@ static struct phy_driver broadcom_driver
|
||||||
|
.ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
.config_intr = bcm_phy_config_intr,
|
||||||
|
}, {
|
||||||
|
+ .phy_id = PHY_ID_BCM54810,
|
||||||
|
+ .phy_id_mask = 0xfffffff0,
|
||||||
|
+ .name = "Broadcom BCM54810",
|
||||||
|
+ .features = PHY_GBIT_FEATURES |
|
||||||
|
+ SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||||
|
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||||
|
+ .config_init = bcm54xx_config_init,
|
||||||
|
+ .config_aneg = bcm5481_config_aneg,
|
||||||
|
+ .read_status = genphy_read_status,
|
||||||
|
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
+ .config_intr = bcm_phy_config_intr,
|
||||||
|
+}, {
|
||||||
|
.phy_id = PHY_ID_BCM5482,
|
||||||
|
.phy_id_mask = 0xfffffff0,
|
||||||
|
.name = "Broadcom BCM5482",
|
||||||
|
@@ -661,6 +716,7 @@ static struct mdio_device_id __maybe_unu
|
||||||
|
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5464, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5481, 0xfffffff0 },
|
||||||
|
+ { PHY_ID_BCM54810, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5482, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM50610, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM50610M, 0xfffffff0 },
|
||||||
|
--- a/drivers/net/phy/Kconfig
|
||||||
|
+++ b/drivers/net/phy/Kconfig
|
||||||
|
@@ -204,7 +204,7 @@ config BROADCOM_PHY
|
||||||
|
select BCM_NET_PHYLIB
|
||||||
|
---help---
|
||||||
|
Currently supports the BCM5411, BCM5421, BCM5461, BCM54616S, BCM5464,
|
||||||
|
- BCM5481 and BCM5482 PHYs.
|
||||||
|
+ BCM5481, BCM54810 and BCM5482 PHYs.
|
||||||
|
|
||||||
|
config CICADA_PHY
|
||||||
|
tristate "Cicada PHYs"
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -13,6 +13,7 @@
|
||||||
|
#define PHY_ID_BCM5241 0x0143bc30
|
||||||
|
#define PHY_ID_BCMAC131 0x0143bc70
|
||||||
|
#define PHY_ID_BCM5481 0x0143bca0
|
||||||
|
+#define PHY_ID_BCM54810 0x03625d00
|
||||||
|
#define PHY_ID_BCM5482 0x0143bcb0
|
||||||
|
#define PHY_ID_BCM5411 0x00206070
|
||||||
|
#define PHY_ID_BCM5421 0x002060e0
|
||||||
|
@@ -56,6 +57,7 @@
|
||||||
|
#define PHY_BRCM_EXT_IBND_TX_ENABLE 0x00002000
|
||||||
|
#define PHY_BRCM_CLEAR_RGMII_MODE 0x00004000
|
||||||
|
#define PHY_BRCM_DIS_TXCRXC_NOENRGY 0x00008000
|
||||||
|
+
|
||||||
|
/* Broadcom BCM7xxx specific workarounds */
|
||||||
|
#define PHY_BRCM_7XXX_REV(x) (((x) >> 8) & 0xff)
|
||||||
|
#define PHY_BRCM_7XXX_PATCH(x) ((x) & 0xff)
|
||||||
|
@@ -111,6 +113,7 @@
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||||
|
+#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
|
||||||
|
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MASK 0x0007
|
||||||
|
|
||||||
|
@@ -192,6 +195,12 @@
|
||||||
|
#define BCM5482_SSD_SGMII_SLAVE_EN 0x0002 /* Slave mode enable */
|
||||||
|
#define BCM5482_SSD_SGMII_SLAVE_AD 0x0001 /* Slave auto-detection */
|
||||||
|
|
||||||
|
+/* BCM54810 Registers */
|
||||||
|
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL (MII_BCM54XX_EXP_SEL_ER + 0x90)
|
||||||
|
+#define BCM54810_EXP_BROADREACH_LRE_MISC_CTL_EN (1 << 0)
|
||||||
|
+#define BCM54810_SHD_CLK_CTL 0x3
|
||||||
|
+#define BCM54810_SHD_CLK_CTL_GTXCLK_EN (1 << 9)
|
||||||
|
+
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
/* Fast Ethernet Transceiver definitions. */
|
|
@ -0,0 +1,74 @@
|
||||||
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Date: Tue, 22 Nov 2016 11:40:54 -0800
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Move bcm54xx_auxctl_{read, write} to
|
||||||
|
common library
|
||||||
|
|
||||||
|
We are going to need these functions to implement support for Broadcom
|
||||||
|
Wirespeed, aka downshift.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
@@ -50,6 +50,23 @@ int bcm_phy_read_exp(struct phy_device *
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bcm_phy_read_exp);
|
||||||
|
|
||||||
|
+int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
|
||||||
|
+{
|
||||||
|
+ /* The register must be written to both the Shadow Register Select and
|
||||||
|
+ * the Shadow Read Register Selector
|
||||||
|
+ */
|
||||||
|
+ phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum |
|
||||||
|
+ regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
|
||||||
|
+ return phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(bcm54xx_auxctl_read);
|
||||||
|
+
|
||||||
|
+int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
|
||||||
|
+{
|
||||||
|
+ return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(bcm54xx_auxctl_write);
|
||||||
|
+
|
||||||
|
int bcm_phy_write_misc(struct phy_device *phydev,
|
||||||
|
u16 reg, u16 chl, u16 val)
|
||||||
|
{
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
@@ -19,6 +19,9 @@
|
||||||
|
int bcm_phy_write_exp(struct phy_device *phydev, u16 reg, u16 val);
|
||||||
|
int bcm_phy_read_exp(struct phy_device *phydev, u16 reg);
|
||||||
|
|
||||||
|
+int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val);
|
||||||
|
+int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum);
|
||||||
|
+
|
||||||
|
int bcm_phy_write_misc(struct phy_device *phydev,
|
||||||
|
u16 reg, u16 chl, u16 value);
|
||||||
|
int bcm_phy_read_misc(struct phy_device *phydev,
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -30,21 +30,6 @@ MODULE_DESCRIPTION("Broadcom PHY driver"
|
||||||
|
MODULE_AUTHOR("Maciej W. Rozycki");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
-static int bcm54xx_auxctl_read(struct phy_device *phydev, u16 regnum)
|
||||||
|
-{
|
||||||
|
- /* The register must be written to both the Shadow Register Select and
|
||||||
|
- * the Shadow Read Register Selector
|
||||||
|
- */
|
||||||
|
- phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum |
|
||||||
|
- regnum << MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT);
|
||||||
|
- return phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static int bcm54xx_auxctl_write(struct phy_device *phydev, u16 regnum, u16 val)
|
||||||
|
-{
|
||||||
|
- return phy_write(phydev, MII_BCM54XX_AUX_CTL, regnum | val);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int bcm54810_config(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int rc, val;
|
|
@ -0,0 +1,87 @@
|
||||||
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Date: Tue, 22 Nov 2016 11:40:56 -0800
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Allow enabling or disabling of EEE
|
||||||
|
|
||||||
|
In preparation for adding support for Wirespeed/downshift, we need to
|
||||||
|
change bcm_phy_eee_enable() to allow enabling or disabling EEE, so make
|
||||||
|
the function take an extra enable/disable boolean parameter and rename
|
||||||
|
it to illustrate it sets EEE, not necessarily just enables it.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm7xxx.c
|
||||||
|
+++ b/drivers/net/phy/bcm7xxx.c
|
||||||
|
@@ -199,7 +199,7 @@ static int bcm7xxx_28nm_config_init(stru
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- ret = bcm_phy_enable_eee(phydev);
|
||||||
|
+ ret = bcm_phy_set_eee(phydev, true);
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm-cygnus.c
|
||||||
|
+++ b/drivers/net/phy/bcm-cygnus.c
|
||||||
|
@@ -104,7 +104,7 @@ static int bcm_cygnus_config_init(struct
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Advertise EEE */
|
||||||
|
- rc = bcm_phy_enable_eee(phydev);
|
||||||
|
+ rc = bcm_phy_set_eee(phydev, true);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
@@ -195,7 +195,7 @@ int bcm_phy_enable_apd(struct phy_device
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bcm_phy_enable_apd);
|
||||||
|
|
||||||
|
-int bcm_phy_enable_eee(struct phy_device *phydev)
|
||||||
|
+int bcm_phy_set_eee(struct phy_device *phydev, bool enable)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
|
||||||
|
@@ -205,7 +205,10 @@ int bcm_phy_enable_eee(struct phy_device
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
- val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
|
||||||
|
+ if (enable)
|
||||||
|
+ val |= LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X;
|
||||||
|
+ else
|
||||||
|
+ val &= ~(LPI_FEATURE_EN | LPI_FEATURE_EN_DIG1000X);
|
||||||
|
|
||||||
|
phy_write_mmd_indirect(phydev, BRCM_CL45VEN_EEE_CONTROL,
|
||||||
|
MDIO_MMD_AN, (u32)val);
|
||||||
|
@@ -216,14 +219,17 @@ int bcm_phy_enable_eee(struct phy_device
|
||||||
|
if (val < 0)
|
||||||
|
return val;
|
||||||
|
|
||||||
|
- val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
|
||||||
|
+ if (enable)
|
||||||
|
+ val |= (MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
|
||||||
|
+ else
|
||||||
|
+ val &= ~(MDIO_AN_EEE_ADV_100TX | MDIO_AN_EEE_ADV_1000T);
|
||||||
|
|
||||||
|
phy_write_mmd_indirect(phydev, BCM_CL45VEN_EEE_ADV,
|
||||||
|
MDIO_MMD_AN, (u32)val);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
-EXPORT_SYMBOL_GPL(bcm_phy_enable_eee);
|
||||||
|
+EXPORT_SYMBOL_GPL(bcm_phy_set_eee);
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Broadcom PHY Library");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
@@ -36,5 +36,5 @@ int bcm_phy_config_intr(struct phy_devic
|
||||||
|
|
||||||
|
int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
|
||||||
|
|
||||||
|
-int bcm_phy_enable_eee(struct phy_device *phydev);
|
||||||
|
+int bcm_phy_set_eee(struct phy_device *phydev, bool enable);
|
||||||
|
#endif /* _LINUX_BCM_PHY_LIB_H */
|
|
@ -0,0 +1,125 @@
|
||||||
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Date: Tue, 29 Nov 2016 09:57:17 -0800
|
||||||
|
Subject: [PATCH] net: phy: broadcom: Add support code for reading PHY counters
|
||||||
|
|
||||||
|
Broadcom PHYs expose a number of PHY error counters: receive errors,
|
||||||
|
false carrier sense, SerDes BER count, local and remote receive errors.
|
||||||
|
Add support code to allow retrieving these error counters. Since the
|
||||||
|
Broadcom PHY library code is used by several drivers, make it possible
|
||||||
|
for them to specify the storage for the software copy of the statistics.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.c
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
#include <linux/mdio.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/phy.h>
|
||||||
|
+#include <linux/ethtool.h>
|
||||||
|
|
||||||
|
#define MII_BCM_CHANNEL_WIDTH 0x2000
|
||||||
|
#define BCM_CL45VEN_EEE_ADV 0x3c
|
||||||
|
@@ -231,6 +232,75 @@ int bcm_phy_set_eee(struct phy_device *p
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(bcm_phy_set_eee);
|
||||||
|
|
||||||
|
+struct bcm_phy_hw_stat {
|
||||||
|
+ const char *string;
|
||||||
|
+ u8 reg;
|
||||||
|
+ u8 shift;
|
||||||
|
+ u8 bits;
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+/* Counters freeze at either 0xffff or 0xff, better than nothing */
|
||||||
|
+static const struct bcm_phy_hw_stat bcm_phy_hw_stats[] = {
|
||||||
|
+ { "phy_receive_errors", MII_BRCM_CORE_BASE12, 0, 16 },
|
||||||
|
+ { "phy_serdes_ber_errors", MII_BRCM_CORE_BASE13, 8, 8 },
|
||||||
|
+ { "phy_false_carrier_sense_errors", MII_BRCM_CORE_BASE13, 0, 8 },
|
||||||
|
+ { "phy_local_rcvr_nok", MII_BRCM_CORE_BASE14, 8, 8 },
|
||||||
|
+ { "phy_remote_rcv_nok", MII_BRCM_CORE_BASE14, 0, 8 },
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+int bcm_phy_get_sset_count(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ return ARRAY_SIZE(bcm_phy_hw_stats);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_sset_count);
|
||||||
|
+
|
||||||
|
+void bcm_phy_get_strings(struct phy_device *phydev, u8 *data)
|
||||||
|
+{
|
||||||
|
+ unsigned int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
|
||||||
|
+ memcpy(data + i * ETH_GSTRING_LEN,
|
||||||
|
+ bcm_phy_hw_stats[i].string, ETH_GSTRING_LEN);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_strings);
|
||||||
|
+
|
||||||
|
+#ifndef UINT64_MAX
|
||||||
|
+#define UINT64_MAX (u64)(~((u64)0))
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+/* Caller is supposed to provide appropriate storage for the library code to
|
||||||
|
+ * access the shadow copy
|
||||||
|
+ */
|
||||||
|
+static u64 bcm_phy_get_stat(struct phy_device *phydev, u64 *shadow,
|
||||||
|
+ unsigned int i)
|
||||||
|
+{
|
||||||
|
+ struct bcm_phy_hw_stat stat = bcm_phy_hw_stats[i];
|
||||||
|
+ int val;
|
||||||
|
+ u64 ret;
|
||||||
|
+
|
||||||
|
+ val = phy_read(phydev, stat.reg);
|
||||||
|
+ if (val < 0) {
|
||||||
|
+ ret = UINT64_MAX;
|
||||||
|
+ } else {
|
||||||
|
+ val >>= stat.shift;
|
||||||
|
+ val = val & ((1 << stat.bits) - 1);
|
||||||
|
+ shadow[i] += val;
|
||||||
|
+ ret = shadow[i];
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
|
||||||
|
+ struct ethtool_stats *stats, u64 *data)
|
||||||
|
+{
|
||||||
|
+ unsigned int i;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < ARRAY_SIZE(bcm_phy_hw_stats); i++)
|
||||||
|
+ data[i] = bcm_phy_get_stat(phydev, shadow, i);
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(bcm_phy_get_stats);
|
||||||
|
+
|
||||||
|
MODULE_DESCRIPTION("Broadcom PHY Library");
|
||||||
|
MODULE_LICENSE("GPL v2");
|
||||||
|
MODULE_AUTHOR("Broadcom Corporation");
|
||||||
|
--- a/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
+++ b/drivers/net/phy/bcm-phy-lib.h
|
||||||
|
@@ -37,4 +37,10 @@ int bcm_phy_config_intr(struct phy_devic
|
||||||
|
int bcm_phy_enable_apd(struct phy_device *phydev, bool dll_pwr_down);
|
||||||
|
|
||||||
|
int bcm_phy_set_eee(struct phy_device *phydev, bool enable);
|
||||||
|
+
|
||||||
|
+int bcm_phy_get_sset_count(struct phy_device *phydev);
|
||||||
|
+void bcm_phy_get_strings(struct phy_device *phydev, u8 *data);
|
||||||
|
+void bcm_phy_get_stats(struct phy_device *phydev, u64 *shadow,
|
||||||
|
+ struct ethtool_stats *stats, u64 *data);
|
||||||
|
+
|
||||||
|
#endif /* _LINUX_BCM_PHY_LIB_H */
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -234,6 +234,9 @@
|
||||||
|
#define LPI_FEATURE_EN_DIG1000X 0x4000
|
||||||
|
|
||||||
|
/* Core register definitions*/
|
||||||
|
+#define MII_BRCM_CORE_BASE12 0x12
|
||||||
|
+#define MII_BRCM_CORE_BASE13 0x13
|
||||||
|
+#define MII_BRCM_CORE_BASE14 0x14
|
||||||
|
#define MII_BRCM_CORE_BASE1E 0x1E
|
||||||
|
#define MII_BRCM_CORE_EXPB0 0xB0
|
||||||
|
#define MII_BRCM_CORE_EXPB1 0xB1
|
|
@ -0,0 +1,38 @@
|
||||||
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Date: Fri, 20 Jan 2017 12:36:33 -0800
|
||||||
|
Subject: [PATCH] net: phy: bcm7xxx: Add entry for BCM7278
|
||||||
|
|
||||||
|
Add support for the BCM7278 28nm process Gigabit Ethernet PHY.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm7xxx.c
|
||||||
|
+++ b/drivers/net/phy/bcm7xxx.c
|
||||||
|
@@ -334,6 +334,7 @@ static int bcm7xxx_suspend(struct phy_de
|
||||||
|
|
||||||
|
static struct phy_driver bcm7xxx_driver[] = {
|
||||||
|
BCM7XXX_28NM_GPHY(PHY_ID_BCM7250, "Broadcom BCM7250"),
|
||||||
|
+ BCM7XXX_28NM_GPHY(PHY_ID_BCM7278, "Broadcom BCM7278"),
|
||||||
|
BCM7XXX_28NM_GPHY(PHY_ID_BCM7364, "Broadcom BCM7364"),
|
||||||
|
BCM7XXX_28NM_GPHY(PHY_ID_BCM7366, "Broadcom BCM7366"),
|
||||||
|
BCM7XXX_28NM_GPHY(PHY_ID_BCM7439, "Broadcom BCM7439"),
|
||||||
|
@@ -348,6 +349,7 @@ static struct phy_driver bcm7xxx_driver[
|
||||||
|
|
||||||
|
static struct mdio_device_id __maybe_unused bcm7xxx_tbl[] = {
|
||||||
|
{ PHY_ID_BCM7250, 0xfffffff0, },
|
||||||
|
+ { PHY_ID_BCM7278, 0xfffffff0, },
|
||||||
|
{ PHY_ID_BCM7364, 0xfffffff0, },
|
||||||
|
{ PHY_ID_BCM7366, 0xfffffff0, },
|
||||||
|
{ PHY_ID_BCM7346, 0xfffffff0, },
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -24,6 +24,7 @@
|
||||||
|
#define PHY_ID_BCM57780 0x03625d90
|
||||||
|
|
||||||
|
#define PHY_ID_BCM7250 0xae025280
|
||||||
|
+#define PHY_ID_BCM7278 0xae0251a0
|
||||||
|
#define PHY_ID_BCM7364 0xae025260
|
||||||
|
#define PHY_ID_BCM7366 0x600d8490
|
||||||
|
#define PHY_ID_BCM7346 0x600d8650
|
|
@ -0,0 +1,68 @@
|
||||||
|
From: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Date: Fri, 20 Jan 2017 12:36:34 -0800
|
||||||
|
Subject: [PATCH] net: phy: bcm7xxx: Implement EGPHY workaround for 7278
|
||||||
|
|
||||||
|
Implement the HW design team recommended workaround in for 7278. Since
|
||||||
|
the GPHY now returns its revision information in MII_PHYS_ID[23] we need
|
||||||
|
to check whether the revision provided in flags is 0 or not.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/bcm7xxx.c
|
||||||
|
+++ b/drivers/net/phy/bcm7xxx.c
|
||||||
|
@@ -163,12 +163,43 @@ static int bcm7xxx_28nm_e0_plus_afe_conf
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int bcm7xxx_28nm_a0_patch_afe_config_init(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ /* +1 RC_CAL codes for RL centering for both LT and HT conditions */
|
||||||
|
+ bcm_phy_write_misc(phydev, AFE_RXCONFIG_2, 0xd003);
|
||||||
|
+
|
||||||
|
+ /* Cut master bias current by 2% to compensate for RC_CAL offset */
|
||||||
|
+ bcm_phy_write_misc(phydev, DSP_TAP10, 0x791b);
|
||||||
|
+
|
||||||
|
+ /* Improve hybrid leakage */
|
||||||
|
+ bcm_phy_write_misc(phydev, AFE_HPF_TRIM_OTHERS, 0x10e3);
|
||||||
|
+
|
||||||
|
+ /* Change rx_on_tune 8 to 0xf */
|
||||||
|
+ bcm_phy_write_misc(phydev, 0x21, 0x2, 0x87f6);
|
||||||
|
+
|
||||||
|
+ /* Change 100Tx EEE bandwidth */
|
||||||
|
+ bcm_phy_write_misc(phydev, 0x22, 0x2, 0x017d);
|
||||||
|
+
|
||||||
|
+ /* Enable ffe zero detection for Vitesse interoperability */
|
||||||
|
+ bcm_phy_write_misc(phydev, 0x26, 0x2, 0x0015);
|
||||||
|
+
|
||||||
|
+ r_rc_cal_reset(phydev);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm7xxx_28nm_config_init(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
u8 rev = PHY_BRCM_7XXX_REV(phydev->dev_flags);
|
||||||
|
u8 patch = PHY_BRCM_7XXX_PATCH(phydev->dev_flags);
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
+ /* Newer devices have moved the revision information back into a
|
||||||
|
+ * standard location in MII_PHYS_ID[23]
|
||||||
|
+ */
|
||||||
|
+ if (rev == 0)
|
||||||
|
+ rev = phydev->phy_id & ~phydev->drv->phy_id_mask;
|
||||||
|
+
|
||||||
|
pr_info_once("%s: %s PHY revision: 0x%02x, patch: %d\n",
|
||||||
|
phydev_name(phydev), phydev->drv->name, rev, patch);
|
||||||
|
|
||||||
|
@@ -192,6 +223,9 @@ static int bcm7xxx_28nm_config_init(stru
|
||||||
|
case 0x10:
|
||||||
|
ret = bcm7xxx_28nm_e0_plus_afe_config_init(phydev);
|
||||||
|
break;
|
||||||
|
+ case 0x01:
|
||||||
|
+ ret = bcm7xxx_28nm_a0_patch_afe_config_init(phydev);
|
||||||
|
+ break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Wed, 25 Jan 2017 21:00:25 +0100
|
||||||
|
Subject: [PATCH] net: phy: broadcom: use auxctl reading helper in BCM54612E
|
||||||
|
code
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Starting with commit 5b4e29005123 ("net: phy: broadcom: add
|
||||||
|
bcm54xx_auxctl_read") we have a reading helper so use it and avoid code
|
||||||
|
duplication.
|
||||||
|
It also means we don't need MII_BCM54XX_AUXCTL_SHDWSEL_MISC define as
|
||||||
|
it's the same as MII_BCM54XX_AUXCTL_SHDWSEL_MISC just for reading needs
|
||||||
|
(same value shifted by 12 bits).
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -395,10 +395,8 @@ static int bcm54612e_config_aneg(struct
|
||||||
|
(phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||||
|
u16 reg;
|
||||||
|
|
||||||
|
- /* Errata: reads require filling in the write selector field */
|
||||||
|
- bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
- MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC);
|
||||||
|
- reg = phy_read(phydev, MII_BCM54XX_AUX_CTL);
|
||||||
|
+ reg = bcm54xx_auxctl_read(phydev,
|
||||||
|
+ MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||||
|
/* Disable RXD to RXC delay (default set) */
|
||||||
|
reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
|
||||||
|
/* Clear shadow selector field */
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -111,7 +111,6 @@
|
||||||
|
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_WREN 0x8000
|
||||||
|
#define MII_BCM54XX_AUXCTL_MISC_FORCE_AMDIX 0x0200
|
||||||
|
-#define MII_BCM54XX_AUXCTL_MISC_RDSEL_MISC 0x7000
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC 0x0007
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_READ_SHIFT 12
|
||||||
|
#define MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN (1 << 8)
|
|
@ -0,0 +1,89 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Fri, 27 Jan 2017 14:07:01 +0100
|
||||||
|
Subject: [PATCH] net: phy: broadcom: add support for BCM54210E
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
It's Broadcom PHY simply described as single-port
|
||||||
|
RGMII 10/100/1000BASE-T PHY. It requires disabling delay skew and GTXCLK
|
||||||
|
bits.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -30,6 +30,22 @@ MODULE_DESCRIPTION("Broadcom PHY driver"
|
||||||
|
MODULE_AUTHOR("Maciej W. Rozycki");
|
||||||
|
MODULE_LICENSE("GPL");
|
||||||
|
|
||||||
|
+static int bcm54210e_config_init(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ int val;
|
||||||
|
+
|
||||||
|
+ val = bcm54xx_auxctl_read(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||||
|
+ val &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||||
|
+ val |= MII_BCM54XX_AUXCTL_MISC_WREN;
|
||||||
|
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC, val);
|
||||||
|
+
|
||||||
|
+ val = bcm_phy_read_shadow(phydev, BCM54810_SHD_CLK_CTL);
|
||||||
|
+ val &= ~BCM54810_SHD_CLK_CTL_GTXCLK_EN;
|
||||||
|
+ bcm_phy_write_shadow(phydev, BCM54810_SHD_CLK_CTL, val);
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm54810_config(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int rc, val;
|
||||||
|
@@ -230,7 +246,11 @@ static int bcm54xx_config_init(struct ph
|
||||||
|
(phydev->dev_flags & PHY_BRCM_AUTO_PWRDWN_ENABLE))
|
||||||
|
bcm54xx_adjust_rxrefclk(phydev);
|
||||||
|
|
||||||
|
- if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||||
|
+ if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54210E) {
|
||||||
|
+ err = bcm54210e_config_init(phydev);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||||
|
err = bcm54810_config(phydev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
@@ -544,6 +564,17 @@ static struct phy_driver broadcom_driver
|
||||||
|
.ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
.config_intr = bcm_phy_config_intr,
|
||||||
|
}, {
|
||||||
|
+ .phy_id = PHY_ID_BCM54210E,
|
||||||
|
+ .phy_id_mask = 0xfffffff0,
|
||||||
|
+ .name = "Broadcom BCM54210E",
|
||||||
|
+ .features = PHY_GBIT_FEATURES,
|
||||||
|
+ .flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||||
|
+ .config_init = bcm54xx_config_init,
|
||||||
|
+ .config_aneg = genphy_config_aneg,
|
||||||
|
+ .read_status = genphy_read_status,
|
||||||
|
+ .ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
+ .config_intr = bcm_phy_config_intr,
|
||||||
|
+}, {
|
||||||
|
.phy_id = PHY_ID_BCM5461,
|
||||||
|
.phy_id_mask = 0xfffffff0,
|
||||||
|
.name = "Broadcom BCM5461",
|
||||||
|
@@ -694,6 +725,7 @@ module_phy_driver(broadcom_drivers);
|
||||||
|
static struct mdio_device_id __maybe_unused broadcom_tbl[] = {
|
||||||
|
{ PHY_ID_BCM5411, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5421, 0xfffffff0 },
|
||||||
|
+ { PHY_ID_BCM54210E, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM5461, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM54612E, 0xfffffff0 },
|
||||||
|
{ PHY_ID_BCM54616S, 0xfffffff0 },
|
||||||
|
--- a/include/linux/brcmphy.h
|
||||||
|
+++ b/include/linux/brcmphy.h
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
#define PHY_ID_BCM5482 0x0143bcb0
|
||||||
|
#define PHY_ID_BCM5411 0x00206070
|
||||||
|
#define PHY_ID_BCM5421 0x002060e0
|
||||||
|
+#define PHY_ID_BCM54210E 0x600d84a0
|
||||||
|
#define PHY_ID_BCM5464 0x002060b0
|
||||||
|
#define PHY_ID_BCM5461 0x002060c0
|
||||||
|
#define PHY_ID_BCM54612E 0x03625e60
|
|
@ -0,0 +1,121 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Date: Tue, 31 Jan 2017 22:54:54 +0100
|
||||||
|
Subject: [PATCH] net: phy: broadcom: rehook BCM54612E specific init
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
This extra BCM54612E code in PHY driver isn't really aneg specific. Even
|
||||||
|
without it aneg works OK but the problem is no packets pass through PHY.
|
||||||
|
|
||||||
|
Moreover putting this code inside config_aneg callback didn't allow
|
||||||
|
resuming PHY correctly. When driver called phy_stop and phy_start it was
|
||||||
|
putting PHY machine into RESUMING state. After that machine was
|
||||||
|
switching into AN and NOLINK without ever calling phy_start_aneg. This
|
||||||
|
prevented this extra setup from being called and PHY didn't work.
|
||||||
|
|
||||||
|
This change has been verified to fix network on BCM47186B0 SoC device
|
||||||
|
with BCM54612E.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
Reviewed-by: Florian Fainelli <f.fainelli@gmail.com>
|
||||||
|
Signed-off-by: David S. Miller <davem@davemloft.net>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/broadcom.c
|
||||||
|
+++ b/drivers/net/phy/broadcom.c
|
||||||
|
@@ -46,6 +46,34 @@ static int bcm54210e_config_init(struct
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int bcm54612e_config_init(struct phy_device *phydev)
|
||||||
|
+{
|
||||||
|
+ /* Clear TX internal delay unless requested. */
|
||||||
|
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||||
|
+ /* Disable TXD to GTXCLK clock delay (default set) */
|
||||||
|
+ /* Bit 9 is the only field in shadow register 00011 */
|
||||||
|
+ bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* Clear RX internal delay unless requested. */
|
||||||
|
+ if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
+ (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||||
|
+ u16 reg;
|
||||||
|
+
|
||||||
|
+ reg = bcm54xx_auxctl_read(phydev,
|
||||||
|
+ MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||||
|
+ /* Disable RXD to RXC delay (default set) */
|
||||||
|
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MISC_RGMII_SKEW_EN;
|
||||||
|
+ /* Clear shadow selector field */
|
||||||
|
+ reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||||
|
+ bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
+ MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm54810_config(struct phy_device *phydev)
|
||||||
|
{
|
||||||
|
int rc, val;
|
||||||
|
@@ -250,6 +278,10 @@ static int bcm54xx_config_init(struct ph
|
||||||
|
err = bcm54210e_config_init(phydev);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
+ } else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54612E) {
|
||||||
|
+ err = bcm54612e_config_init(phydev);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
} else if (BRCM_PHY_MODEL(phydev) == PHY_ID_BCM54810) {
|
||||||
|
err = bcm54810_config(phydev);
|
||||||
|
if (err)
|
||||||
|
@@ -395,39 +427,6 @@ static int bcm5481_config_aneg(struct ph
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static int bcm54612e_config_aneg(struct phy_device *phydev)
|
||||||
|
-{
|
||||||
|
- int ret;
|
||||||
|
-
|
||||||
|
- /* First, auto-negotiate. */
|
||||||
|
- ret = genphy_config_aneg(phydev);
|
||||||
|
-
|
||||||
|
- /* Clear TX internal delay unless requested. */
|
||||||
|
- if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
- (phydev->interface != PHY_INTERFACE_MODE_RGMII_TXID)) {
|
||||||
|
- /* Disable TXD to GTXCLK clock delay (default set) */
|
||||||
|
- /* Bit 9 is the only field in shadow register 00011 */
|
||||||
|
- bcm_phy_write_shadow(phydev, 0x03, 0);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /* Clear RX internal delay unless requested. */
|
||||||
|
- if ((phydev->interface != PHY_INTERFACE_MODE_RGMII_ID) &&
|
||||||
|
- (phydev->interface != PHY_INTERFACE_MODE_RGMII_RXID)) {
|
||||||
|
- u16 reg;
|
||||||
|
-
|
||||||
|
- reg = bcm54xx_auxctl_read(phydev,
|
||||||
|
- MII_BCM54XX_AUXCTL_SHDWSEL_MISC);
|
||||||
|
- /* Disable RXD to RXC delay (default set) */
|
||||||
|
- reg &= ~MII_BCM54XX_AUXCTL_MISC_RXD_RXC_SKEW;
|
||||||
|
- /* Clear shadow selector field */
|
||||||
|
- reg &= ~MII_BCM54XX_AUXCTL_SHDWSEL_MASK;
|
||||||
|
- bcm54xx_auxctl_write(phydev, MII_BCM54XX_AUXCTL_SHDWSEL_MISC,
|
||||||
|
- MII_BCM54XX_AUXCTL_MISC_WREN | reg);
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- return ret;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static int brcm_phy_setbits(struct phy_device *phydev, int reg, int set)
|
||||||
|
{
|
||||||
|
int val;
|
||||||
|
@@ -594,7 +593,7 @@ static struct phy_driver broadcom_driver
|
||||||
|
SUPPORTED_Pause | SUPPORTED_Asym_Pause,
|
||||||
|
.flags = PHY_HAS_MAGICANEG | PHY_HAS_INTERRUPT,
|
||||||
|
.config_init = bcm54xx_config_init,
|
||||||
|
- .config_aneg = bcm54612e_config_aneg,
|
||||||
|
+ .config_aneg = genphy_config_aneg,
|
||||||
|
.read_status = genphy_read_status,
|
||||||
|
.ack_interrupt = bcm_phy_ack_intr,
|
||||||
|
.config_intr = bcm_phy_config_intr,
|
|
@ -0,0 +1,31 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Sun, 24 Jan 2016 01:03:51 +0100
|
||||||
|
Subject: [PATCH] MIPS: fix cache flushing for highmem pages
|
||||||
|
|
||||||
|
Most cache flush ops were no-op for highmem pages. This led to nasty
|
||||||
|
segfaults and (in the case of page_address(page) == NULL) kernel
|
||||||
|
crashes.
|
||||||
|
|
||||||
|
Fix this by always flushing highmem pages using kmap/kunmap_atomic
|
||||||
|
around the actual cache flush. This might be a bit inefficient, but at
|
||||||
|
least it's stable.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/mm/cache.c
|
||||||
|
+++ b/arch/mips/mm/cache.c
|
||||||
|
@@ -115,6 +115,13 @@ void __flush_anon_page(struct page *page
|
||||||
|
{
|
||||||
|
unsigned long addr = (unsigned long) page_address(page);
|
||||||
|
|
||||||
|
+ if (PageHighMem(page)) {
|
||||||
|
+ addr = (unsigned long)kmap_atomic(page);
|
||||||
|
+ flush_data_cache_page(addr);
|
||||||
|
+ __kunmap_atomic((void *)addr);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (pages_do_alias(addr, vmaddr)) {
|
||||||
|
if (page_mapcount(page) && !Page_dcache_dirty(page)) {
|
||||||
|
void *kaddr;
|
|
@ -0,0 +1,82 @@
|
||||||
|
From 1e311820ec3055e3f08e687de6564692a7cec675 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Florian Fainelli <florian@openwrt.org>
|
||||||
|
Date: Mon, 28 Jan 2013 20:06:29 +0100
|
||||||
|
Subject: [PATCH 11/12] USB: EHCI: add ignore_oc flag to disable overcurrent
|
||||||
|
checking
|
||||||
|
|
||||||
|
This patch adds an ignore_oc flag which can be set by EHCI controller
|
||||||
|
not supporting or wanting to disable overcurrent checking. The EHCI
|
||||||
|
platform data in include/linux/usb/ehci_pdriver.h is also augmented to
|
||||||
|
take advantage of this new flag.
|
||||||
|
|
||||||
|
Signed-off-by: Florian Fainelli <florian@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/usb/host/ehci-hcd.c | 2 +-
|
||||||
|
drivers/usb/host/ehci-hub.c | 4 ++--
|
||||||
|
drivers/usb/host/ehci-platform.c | 1 +
|
||||||
|
drivers/usb/host/ehci.h | 1 +
|
||||||
|
include/linux/usb/ehci_pdriver.h | 1 +
|
||||||
|
5 files changed, 6 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/usb/host/ehci-hcd.c
|
||||||
|
+++ b/drivers/usb/host/ehci-hcd.c
|
||||||
|
@@ -651,7 +651,7 @@ static int ehci_run (struct usb_hcd *hcd
|
||||||
|
"USB %x.%x started, EHCI %x.%02x%s\n",
|
||||||
|
((ehci->sbrn & 0xf0)>>4), (ehci->sbrn & 0x0f),
|
||||||
|
temp >> 8, temp & 0xff,
|
||||||
|
- ignore_oc ? ", overcurrent ignored" : "");
|
||||||
|
+ (ignore_oc || ehci->ignore_oc) ? ", overcurrent ignored" : "");
|
||||||
|
|
||||||
|
ehci_writel(ehci, INTR_MASK,
|
||||||
|
&ehci->regs->intr_enable); /* Turn On Interrupts */
|
||||||
|
--- a/drivers/usb/host/ehci-hub.c
|
||||||
|
+++ b/drivers/usb/host/ehci-hub.c
|
||||||
|
@@ -638,7 +638,7 @@ ehci_hub_status_data (struct usb_hcd *hc
|
||||||
|
* always set, seem to clear PORT_OCC and PORT_CSC when writing to
|
||||||
|
* PORT_POWER; that's surprising, but maybe within-spec.
|
||||||
|
*/
|
||||||
|
- if (!ignore_oc)
|
||||||
|
+ if (!ignore_oc && !ehci->ignore_oc)
|
||||||
|
mask = PORT_CSC | PORT_PEC | PORT_OCC;
|
||||||
|
else
|
||||||
|
mask = PORT_CSC | PORT_PEC;
|
||||||
|
@@ -1008,7 +1008,7 @@ int ehci_hub_control(
|
||||||
|
if (temp & PORT_PEC)
|
||||||
|
status |= USB_PORT_STAT_C_ENABLE << 16;
|
||||||
|
|
||||||
|
- if ((temp & PORT_OCC) && !ignore_oc){
|
||||||
|
+ if ((temp & PORT_OCC) && (!ignore_oc && !ehci->ignore_oc)){
|
||||||
|
status |= USB_PORT_STAT_C_OVERCURRENT << 16;
|
||||||
|
|
||||||
|
/*
|
||||||
|
--- a/drivers/usb/host/ehci-platform.c
|
||||||
|
+++ b/drivers/usb/host/ehci-platform.c
|
||||||
|
@@ -259,6 +259,8 @@ static int ehci_platform_probe(struct pl
|
||||||
|
hcd->has_tt = 1;
|
||||||
|
if (pdata->reset_on_resume)
|
||||||
|
priv->reset_on_resume = true;
|
||||||
|
+ if (pdata->ignore_oc)
|
||||||
|
+ ehci->ignore_oc = 1;
|
||||||
|
|
||||||
|
#ifndef CONFIG_USB_EHCI_BIG_ENDIAN_MMIO
|
||||||
|
if (ehci->big_endian_mmio) {
|
||||||
|
--- a/drivers/usb/host/ehci.h
|
||||||
|
+++ b/drivers/usb/host/ehci.h
|
||||||
|
@@ -230,6 +230,7 @@ struct ehci_hcd { /* one per controlle
|
||||||
|
unsigned frame_index_bug:1; /* MosChip (AKA NetMos) */
|
||||||
|
unsigned need_oc_pp_cycle:1; /* MPC834X port power */
|
||||||
|
unsigned imx28_write_fix:1; /* For Freescale i.MX28 */
|
||||||
|
+ unsigned ignore_oc:1;
|
||||||
|
|
||||||
|
/* required for usb32 quirk */
|
||||||
|
#define OHCI_CTRL_HCFS (3 << 6)
|
||||||
|
--- a/include/linux/usb/ehci_pdriver.h
|
||||||
|
+++ b/include/linux/usb/ehci_pdriver.h
|
||||||
|
@@ -49,6 +49,7 @@ struct usb_ehci_pdata {
|
||||||
|
unsigned no_io_watchdog:1;
|
||||||
|
unsigned reset_on_resume:1;
|
||||||
|
unsigned dma_mask_64:1;
|
||||||
|
+ unsigned ignore_oc:1;
|
||||||
|
|
||||||
|
/* Turn on all power and clocks */
|
||||||
|
int (*power_on)(struct platform_device *pdev);
|
|
@ -0,0 +1,86 @@
|
||||||
|
From: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
Date: Wed, 30 Nov 2016 09:16:41 +0100
|
||||||
|
Subject: [PATCH] mm: Fix alloc_node_mem_map with ARCH_PFN_OFFSET
|
||||||
|
calculation
|
||||||
|
|
||||||
|
Dear folks,
|
||||||
|
|
||||||
|
An rt288x (ralink) based router (Belkin F5D8235 v1) does not boot with any
|
||||||
|
kernel beyond version 4.3 resulting in:
|
||||||
|
|
||||||
|
BUG: Bad page state in process swapper pfn:086ac
|
||||||
|
|
||||||
|
bisect resulted in:
|
||||||
|
|
||||||
|
a1c34a3bf00af2cede839879502e12dc68491ad5 is the first bad commit
|
||||||
|
commit a1c34a3bf00af2cede839879502e12dc68491ad5
|
||||||
|
Author: Laura Abbott <laura@labbott.name>
|
||||||
|
Date: Thu Nov 5 18:48:46 2015 -0800
|
||||||
|
|
||||||
|
mm: Don't offset memmap for flatmem
|
||||||
|
|
||||||
|
Srinivas Kandagatla reported bad page messages when trying to remove the
|
||||||
|
bottom 2MB on an ARM based IFC6410 board
|
||||||
|
|
||||||
|
BUG: Bad page state in process swapper pfn:fffa8
|
||||||
|
page:ef7fb500 count:0 mapcount:0 mapping: (null) index:0x0
|
||||||
|
flags: 0x96640253(locked|error|dirty|active|arch_1|reclaim|mlocked)
|
||||||
|
page dumped because: PAGE_FLAGS_CHECK_AT_FREE flag(s) set
|
||||||
|
bad because of flags:
|
||||||
|
flags: 0x200041(locked|active|mlocked)
|
||||||
|
Modules linked in:
|
||||||
|
CPU: 0 PID: 0 Comm: swapper Not tainted 3.19.0-rc3-00007-g412f9ba-dirty
|
||||||
|
#816
|
||||||
|
Hardware name: Qualcomm (Flattened Device Tree)
|
||||||
|
unwind_backtrace
|
||||||
|
show_stack
|
||||||
|
dump_stack
|
||||||
|
bad_page
|
||||||
|
free_pages_prepare
|
||||||
|
free_hot_cold_page
|
||||||
|
__free_pages
|
||||||
|
free_highmem_page
|
||||||
|
mem_init
|
||||||
|
start_kernel
|
||||||
|
Disabling lock debugging due to kernel taint
|
||||||
|
[...]
|
||||||
|
:040000 040000 2de013c372345fd471cd58f0553c9b38b0ef1cc4
|
||||||
|
0a8156f848733dfa21e16c196dfb6c0a76290709 M mm
|
||||||
|
|
||||||
|
This fix for ARM does not account ARCH_PFN_OFFSET for mem_map as later used by
|
||||||
|
page_to_pfn anymore.
|
||||||
|
|
||||||
|
The following output was generated with two hacked in printk statements:
|
||||||
|
|
||||||
|
printk("before %p vs. %p or %p\n", mem_map, mem_map - offset, mem_map -
|
||||||
|
(pgdat->node_start_pfn - ARCH_PFN_OFFSET));
|
||||||
|
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||||
|
mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||||
|
printk("after %p\n", mem_map);
|
||||||
|
|
||||||
|
Output:
|
||||||
|
|
||||||
|
[ 0.000000] before 8861b280 vs. 8861b280 or 8851b280
|
||||||
|
[ 0.000000] after 8851b280
|
||||||
|
|
||||||
|
As seen in the first line mem_map with subtraction of offset does not equal the
|
||||||
|
mem_map after subtraction of ARCH_PFN_OFFSET.
|
||||||
|
|
||||||
|
After adding the offset of ARCH_PFN_OFFSET as well to mem_map as the
|
||||||
|
previously calculated offset is zero for the named platform it is able to boot
|
||||||
|
4.4 and 4.9-rc7 again.
|
||||||
|
|
||||||
|
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/mm/page_alloc.c
|
||||||
|
+++ b/mm/page_alloc.c
|
||||||
|
@@ -5893,7 +5893,7 @@ static void __ref alloc_node_mem_map(str
|
||||||
|
mem_map = NODE_DATA(0)->node_mem_map;
|
||||||
|
#if defined(CONFIG_HAVE_MEMBLOCK_NODE_MAP) || defined(CONFIG_FLATMEM)
|
||||||
|
if (page_to_pfn(mem_map) != pgdat->node_start_pfn)
|
||||||
|
- mem_map -= offset;
|
||||||
|
+ mem_map -= offset + (pgdat->node_start_pfn - ARCH_PFN_OFFSET);
|
||||||
|
#endif /* CONFIG_HAVE_MEMBLOCK_NODE_MAP */
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -0,0 +1,30 @@
|
||||||
|
From: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
Date: Wed, 23 Nov 2016 10:40:07 +0100
|
||||||
|
Subject: [PATCH] of: Add check to of_scan_flat_dt() before accessing
|
||||||
|
initial_boot_params
|
||||||
|
|
||||||
|
An empty __dtb_start to __dtb_end section might result in initial_boot_params
|
||||||
|
being null for arch/mips/ralink. This showed that the boot process hangs
|
||||||
|
indefinitely in of_scan_flat_dt().
|
||||||
|
|
||||||
|
Signed-off-by: Tobias Wolf <dev-NTEO@vplace.de>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/of/fdt.c
|
||||||
|
+++ b/drivers/of/fdt.c
|
||||||
|
@@ -738,9 +738,12 @@ int __init of_scan_flat_dt(int (*it)(uns
|
||||||
|
const char *pathp;
|
||||||
|
int offset, rc = 0, depth = -1;
|
||||||
|
|
||||||
|
- for (offset = fdt_next_node(blob, -1, &depth);
|
||||||
|
- offset >= 0 && depth >= 0 && !rc;
|
||||||
|
- offset = fdt_next_node(blob, offset, &depth)) {
|
||||||
|
+ if (!blob)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ for (offset = fdt_next_node(blob, -1, &depth);
|
||||||
|
+ offset >= 0 && depth >= 0 && !rc;
|
||||||
|
+ offset = fdt_next_node(blob, offset, &depth)) {
|
||||||
|
|
||||||
|
pathp = fdt_get_name(blob, offset, NULL);
|
||||||
|
if (*pathp == '/')
|
|
@ -0,0 +1,15 @@
|
||||||
|
Add the linux,spidev compatible in spidev
|
||||||
|
Several device in ramips have this binding in the dts
|
||||||
|
|
||||||
|
Signed-off-by: Giuseppe Lippolis <giu.lippolis@gmail.com>
|
||||||
|
---
|
||||||
|
--- a/drivers/spi/spidev.c
|
||||||
|
+++ b/drivers/spi/spidev.c
|
||||||
|
@@ -696,6 +696,7 @@ static struct class *spidev_class;
|
||||||
|
static const struct of_device_id spidev_dt_ids[] = {
|
||||||
|
{ .compatible = "rohm,dh2228fv" },
|
||||||
|
{ .compatible = "lineartechnology,ltc2488" },
|
||||||
|
+ { .compatible = "siliconlabs,si3210" },
|
||||||
|
{},
|
||||||
|
};
|
||||||
|
MODULE_DEVICE_TABLE(of, spidev_dt_ids);
|
|
@ -0,0 +1,21 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Fri, 30 Dec 2016 14:53:45 +0100
|
||||||
|
Subject: [PATCH] spi: use gpio_set_value_cansleep for setting chipselect GPIO
|
||||||
|
|
||||||
|
Sleeping is safe inside spi_transfer_one_message, and some GPIO chips
|
||||||
|
need to sleep for setting values
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/spi/spi.c
|
||||||
|
+++ b/drivers/spi/spi.c
|
||||||
|
@@ -698,7 +698,7 @@ static void spi_set_cs(struct spi_device
|
||||||
|
enable = !enable;
|
||||||
|
|
||||||
|
if (gpio_is_valid(spi->cs_gpio))
|
||||||
|
- gpio_set_value(spi->cs_gpio, !enable);
|
||||||
|
+ gpio_set_value_cansleep(spi->cs_gpio, !enable);
|
||||||
|
else if (spi->master->set_cs)
|
||||||
|
spi->master->set_cs(spi, !enable);
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Fri, 10 Apr 2015 13:35:29 +0200
|
||||||
|
Subject: [PATCH] jffs2: use .rename2 and add RENAME_WHITEOUT support
|
||||||
|
|
||||||
|
It is required for renames on overlayfs
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/fs/jffs2/dir.c
|
||||||
|
+++ b/fs/jffs2/dir.c
|
||||||
|
@@ -756,6 +756,24 @@ static int jffs2_mknod (struct inode *di
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int jffs2_whiteout (struct inode *old_dir, struct dentry *old_dentry)
|
||||||
|
+{
|
||||||
|
+ struct dentry *wh;
|
||||||
|
+ int err;
|
||||||
|
+
|
||||||
|
+ wh = d_alloc(old_dentry->d_parent, &old_dentry->d_name);
|
||||||
|
+ if (!wh)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ err = jffs2_mknod(old_dir, wh, S_IFCHR | WHITEOUT_MODE,
|
||||||
|
+ WHITEOUT_DEV);
|
||||||
|
+ if (err)
|
||||||
|
+ return err;
|
||||||
|
+
|
||||||
|
+ d_rehash(wh);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int jffs2_rename (struct inode *old_dir_i, struct dentry *old_dentry,
|
||||||
|
struct inode *new_dir_i, struct dentry *new_dentry,
|
||||||
|
unsigned int flags)
|
||||||
|
@@ -766,7 +784,7 @@ static int jffs2_rename (struct inode *o
|
||||||
|
uint8_t type;
|
||||||
|
uint32_t now;
|
||||||
|
|
||||||
|
- if (flags & ~RENAME_NOREPLACE)
|
||||||
|
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* The VFS will check for us and prevent trying to rename a
|
||||||
|
@@ -832,9 +850,14 @@ static int jffs2_rename (struct inode *o
|
||||||
|
if (d_is_dir(old_dentry) && !victim_f)
|
||||||
|
inc_nlink(new_dir_i);
|
||||||
|
|
||||||
|
- /* Unlink the original */
|
||||||
|
- ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||||
|
- old_dentry->d_name.name, old_dentry->d_name.len, NULL, now);
|
||||||
|
+ if (flags & RENAME_WHITEOUT)
|
||||||
|
+ /* Replace with whiteout */
|
||||||
|
+ ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||||
|
+ else
|
||||||
|
+ /* Unlink the original */
|
||||||
|
+ ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||||
|
+ old_dentry->d_name.name,
|
||||||
|
+ old_dentry->d_name.len, NULL, now);
|
||||||
|
|
||||||
|
/* We don't touch inode->i_nlink */
|
||||||
|
|
|
@ -0,0 +1,58 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Sat, 25 Apr 2015 12:41:32 +0200
|
||||||
|
Subject: [PATCH] jffs2: add RENAME_EXCHANGE support
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/fs/jffs2/dir.c
|
||||||
|
+++ b/fs/jffs2/dir.c
|
||||||
|
@@ -784,7 +784,7 @@ static int jffs2_rename (struct inode *o
|
||||||
|
uint8_t type;
|
||||||
|
uint32_t now;
|
||||||
|
|
||||||
|
- if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT))
|
||||||
|
+ if (flags & ~(RENAME_NOREPLACE|RENAME_WHITEOUT|RENAME_EXCHANGE))
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
/* The VFS will check for us and prevent trying to rename a
|
||||||
|
@@ -792,7 +792,7 @@ static int jffs2_rename (struct inode *o
|
||||||
|
* the VFS can't check whether the victim is empty. The filesystem
|
||||||
|
* needs to do that for itself.
|
||||||
|
*/
|
||||||
|
- if (d_really_is_positive(new_dentry)) {
|
||||||
|
+ if (d_really_is_positive(new_dentry) && !(flags & RENAME_EXCHANGE)) {
|
||||||
|
victim_f = JFFS2_INODE_INFO(d_inode(new_dentry));
|
||||||
|
if (d_is_dir(new_dentry)) {
|
||||||
|
struct jffs2_full_dirent *fd;
|
||||||
|
@@ -827,7 +827,7 @@ static int jffs2_rename (struct inode *o
|
||||||
|
if (ret)
|
||||||
|
return ret;
|
||||||
|
|
||||||
|
- if (victim_f) {
|
||||||
|
+ if (victim_f && !(flags & RENAME_EXCHANGE)) {
|
||||||
|
/* There was a victim. Kill it off nicely */
|
||||||
|
if (d_is_dir(new_dentry))
|
||||||
|
clear_nlink(d_inode(new_dentry));
|
||||||
|
@@ -853,6 +853,12 @@ static int jffs2_rename (struct inode *o
|
||||||
|
if (flags & RENAME_WHITEOUT)
|
||||||
|
/* Replace with whiteout */
|
||||||
|
ret = jffs2_whiteout(old_dir_i, old_dentry);
|
||||||
|
+ else if (flags & RENAME_EXCHANGE)
|
||||||
|
+ /* Replace the original */
|
||||||
|
+ ret = jffs2_do_link(c, JFFS2_INODE_INFO(old_dir_i),
|
||||||
|
+ d_inode(new_dentry)->i_ino, type,
|
||||||
|
+ old_dentry->d_name.name, old_dentry->d_name.len,
|
||||||
|
+ now);
|
||||||
|
else
|
||||||
|
/* Unlink the original */
|
||||||
|
ret = jffs2_do_unlink(c, JFFS2_INODE_INFO(old_dir_i),
|
||||||
|
@@ -884,7 +890,7 @@ static int jffs2_rename (struct inode *o
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
- if (d_is_dir(old_dentry))
|
||||||
|
+ if (d_is_dir(old_dentry) && !(flags & RENAME_EXCHANGE))
|
||||||
|
drop_nlink(old_dir_i);
|
||||||
|
|
||||||
|
new_dir_i->i_mtime = new_dir_i->i_ctime = old_dir_i->i_mtime = old_dir_i->i_ctime = ITIME(now);
|
|
@ -0,0 +1,43 @@
|
||||||
|
From: Stephen Hemminger <stephen@networkplumber.org>
|
||||||
|
Subject: bridge: allow receiption on disabled port
|
||||||
|
|
||||||
|
When an ethernet device is enslaved to a bridge, and the bridge STP
|
||||||
|
detects loss of carrier (or operational state down), then normally
|
||||||
|
packet receiption is blocked.
|
||||||
|
|
||||||
|
This breaks control applications like WPA which maybe expecting to
|
||||||
|
receive packets to negotiate to bring link up. The bridge needs to
|
||||||
|
block forwarding packets from these disabled ports, but there is no
|
||||||
|
hard requirement to not allow local packet delivery.
|
||||||
|
|
||||||
|
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
|
--- a/net/bridge/br_input.c
|
||||||
|
+++ b/net/bridge/br_input.c
|
||||||
|
@@ -232,7 +232,8 @@ static int br_handle_local_finish(struct
|
||||||
|
{
|
||||||
|
struct net_bridge_port *p = br_port_get_rcu(skb->dev);
|
||||||
|
|
||||||
|
- __br_handle_local_finish(skb);
|
||||||
|
+ if (p->state != BR_STATE_DISABLED)
|
||||||
|
+ __br_handle_local_finish(skb);
|
||||||
|
|
||||||
|
BR_INPUT_SKB_CB(skb)->brdev = p->br->dev;
|
||||||
|
br_pass_frame_up(skb);
|
||||||
|
@@ -315,6 +316,15 @@ rx_handler_result_t br_handle_frame(stru
|
||||||
|
|
||||||
|
forward:
|
||||||
|
switch (p->state) {
|
||||||
|
+ case BR_STATE_DISABLED:
|
||||||
|
+ if (ether_addr_equal(p->br->dev->dev_addr, dest))
|
||||||
|
+ skb->pkt_type = PACKET_HOST;
|
||||||
|
+
|
||||||
|
+ NF_HOOK(NFPROTO_BRIDGE, NF_BR_PRE_ROUTING,
|
||||||
|
+ dev_net(skb->dev), NULL, skb, skb->dev, NULL,
|
||||||
|
+ br_handle_local_finish);
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
case BR_STATE_FORWARDING:
|
||||||
|
rhook = rcu_dereference(br_should_route_hook);
|
||||||
|
if (rhook) {
|
|
@ -0,0 +1,183 @@
|
||||||
|
From 3e7056c3a369e9ef9ca804bc626b60ef6b62ee27 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Hauke Mehrtens <hauke@hauke-m.de>
|
||||||
|
Date: Sun, 17 May 2015 18:48:38 +0200
|
||||||
|
Subject: [PATCH 2/3] mtd: part: add generic parsing of linux,part-probe
|
||||||
|
|
||||||
|
This moves the linux,part-probe device tree parsing code from
|
||||||
|
physmap_of.c to mtdpart.c. Now all drivers can use this feature by just
|
||||||
|
providing a reference to their device tree node in struct
|
||||||
|
mtd_part_parser_data.
|
||||||
|
|
||||||
|
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
|
||||||
|
---
|
||||||
|
Documentation/devicetree/bindings/mtd/nand.txt | 16 +++++++++
|
||||||
|
drivers/mtd/maps/physmap_of.c | 46 +-------------------------
|
||||||
|
drivers/mtd/mtdpart.c | 45 +++++++++++++++++++++++++
|
||||||
|
3 files changed, 62 insertions(+), 45 deletions(-)
|
||||||
|
|
||||||
|
--- a/Documentation/devicetree/bindings/mtd/nand.txt
|
||||||
|
+++ b/Documentation/devicetree/bindings/mtd/nand.txt
|
||||||
|
@@ -44,6 +44,22 @@ Optional NAND chip properties:
|
||||||
|
used by the upper layers, and you want to make your NAND
|
||||||
|
as reliable as possible.
|
||||||
|
|
||||||
|
+- linux,part-probe: list of name as strings of the partition parser
|
||||||
|
+ which should be used to parse the partition table.
|
||||||
|
+ They will be tried in the specified ordering and
|
||||||
|
+ the next one will be used if the previous one
|
||||||
|
+ failed.
|
||||||
|
+
|
||||||
|
+ Example: linux,part-probe = "cmdlinepart", "ofpart";
|
||||||
|
+
|
||||||
|
+ This is also the default value, which will be used
|
||||||
|
+ if this attribute is not specified. It could be
|
||||||
|
+ that the flash driver in use overwrote the default
|
||||||
|
+ value and uses some other default.
|
||||||
|
+
|
||||||
|
+ Possible values are: bcm47xxpart, afs, ar7part,
|
||||||
|
+ ofoldpart, ofpart, bcm63xxpart, RedBoot, cmdlinepart
|
||||||
|
+
|
||||||
|
The ECC strength and ECC step size properties define the correction capability
|
||||||
|
of a controller. Together, they say a controller can correct "{strength} bit
|
||||||
|
errors per {size} bytes".
|
||||||
|
--- a/drivers/mtd/maps/physmap_of.c
|
||||||
|
+++ b/drivers/mtd/maps/physmap_of.c
|
||||||
|
@@ -113,47 +113,9 @@ static struct mtd_info *obsolete_probe(s
|
||||||
|
static const char * const part_probe_types_def[] = {
|
||||||
|
"cmdlinepart", "RedBoot", "ofpart", "ofoldpart", NULL };
|
||||||
|
|
||||||
|
-static const char * const *of_get_probes(struct device_node *dp)
|
||||||
|
-{
|
||||||
|
- const char *cp;
|
||||||
|
- int cplen;
|
||||||
|
- unsigned int l;
|
||||||
|
- unsigned int count;
|
||||||
|
- const char **res;
|
||||||
|
-
|
||||||
|
- cp = of_get_property(dp, "linux,part-probe", &cplen);
|
||||||
|
- if (cp == NULL)
|
||||||
|
- return part_probe_types_def;
|
||||||
|
-
|
||||||
|
- count = 0;
|
||||||
|
- for (l = 0; l != cplen; l++)
|
||||||
|
- if (cp[l] == 0)
|
||||||
|
- count++;
|
||||||
|
-
|
||||||
|
- res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
|
||||||
|
- if (!res)
|
||||||
|
- return NULL;
|
||||||
|
- count = 0;
|
||||||
|
- while (cplen > 0) {
|
||||||
|
- res[count] = cp;
|
||||||
|
- l = strlen(cp) + 1;
|
||||||
|
- cp += l;
|
||||||
|
- cplen -= l;
|
||||||
|
- count++;
|
||||||
|
- }
|
||||||
|
- return res;
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-static void of_free_probes(const char * const *probes)
|
||||||
|
-{
|
||||||
|
- if (probes != part_probe_types_def)
|
||||||
|
- kfree(probes);
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
static const struct of_device_id of_flash_match[];
|
||||||
|
static int of_flash_probe(struct platform_device *dev)
|
||||||
|
{
|
||||||
|
- const char * const *part_probe_types;
|
||||||
|
const struct of_device_id *match;
|
||||||
|
struct device_node *dp = dev->dev.of_node;
|
||||||
|
struct resource res;
|
||||||
|
@@ -317,14 +279,8 @@ static int of_flash_probe(struct platfor
|
||||||
|
|
||||||
|
info->cmtd->dev.parent = &dev->dev;
|
||||||
|
mtd_set_of_node(info->cmtd, dp);
|
||||||
|
- part_probe_types = of_get_probes(dp);
|
||||||
|
- if (!part_probe_types) {
|
||||||
|
- err = -ENOMEM;
|
||||||
|
- goto err_out;
|
||||||
|
- }
|
||||||
|
- mtd_device_parse_register(info->cmtd, part_probe_types, NULL,
|
||||||
|
+ mtd_device_parse_register(info->cmtd, part_probe_types_def, NULL,
|
||||||
|
NULL, 0);
|
||||||
|
- of_free_probes(part_probe_types);
|
||||||
|
|
||||||
|
kfree(mtd_list);
|
||||||
|
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -29,6 +29,7 @@
|
||||||
|
#include <linux/kmod.h>
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/of.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
|
||||||
|
#include "mtdcore.h"
|
||||||
|
@@ -779,6 +780,42 @@ void deregister_mtd_parser(struct mtd_pa
|
||||||
|
EXPORT_SYMBOL_GPL(deregister_mtd_parser);
|
||||||
|
|
||||||
|
/*
|
||||||
|
+ * Parses the linux,part-probe device tree property.
|
||||||
|
+ * When a non null value is returned it has to be freed with kfree() by
|
||||||
|
+ * the caller.
|
||||||
|
+ */
|
||||||
|
+static const char * const *of_get_probes(struct device_node *dp)
|
||||||
|
+{
|
||||||
|
+ const char *cp;
|
||||||
|
+ int cplen;
|
||||||
|
+ unsigned int l;
|
||||||
|
+ unsigned int count;
|
||||||
|
+ const char **res;
|
||||||
|
+
|
||||||
|
+ cp = of_get_property(dp, "linux,part-probe", &cplen);
|
||||||
|
+ if (cp == NULL)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ count = 0;
|
||||||
|
+ for (l = 0; l != cplen; l++)
|
||||||
|
+ if (cp[l] == 0)
|
||||||
|
+ count++;
|
||||||
|
+
|
||||||
|
+ res = kzalloc((count + 1) * sizeof(*res), GFP_KERNEL);
|
||||||
|
+ if (!res)
|
||||||
|
+ return NULL;
|
||||||
|
+ count = 0;
|
||||||
|
+ while (cplen > 0) {
|
||||||
|
+ res[count] = cp;
|
||||||
|
+ l = strlen(cp) + 1;
|
||||||
|
+ cp += l;
|
||||||
|
+ cplen -= l;
|
||||||
|
+ count++;
|
||||||
|
+ }
|
||||||
|
+ return res;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/*
|
||||||
|
* Do not forget to update 'parse_mtd_partitions()' kerneldoc comment if you
|
||||||
|
* are changing this array!
|
||||||
|
*/
|
||||||
|
@@ -815,6 +852,13 @@ int parse_mtd_partitions(struct mtd_info
|
||||||
|
{
|
||||||
|
struct mtd_part_parser *parser;
|
||||||
|
int ret, err = 0;
|
||||||
|
+ const char *const *types_of = NULL;
|
||||||
|
+
|
||||||
|
+ if (mtd_get_of_node(master)) {
|
||||||
|
+ types_of = of_get_probes(mtd_get_of_node(master));
|
||||||
|
+ if (types_of != NULL)
|
||||||
|
+ types = types_of;
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (!types)
|
||||||
|
types = default_mtd_part_types;
|
||||||
|
@@ -846,6 +890,7 @@ int parse_mtd_partitions(struct mtd_info
|
||||||
|
if (ret < 0 && !err)
|
||||||
|
err = ret;
|
||||||
|
}
|
||||||
|
+ kfree(types_of);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,177 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Subject: [PATCH 1/2] mtd: bcm47xxpart: move TRX parsing code to separated
|
||||||
|
function
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
This change simplifies main parsing loop logic a bit. In future it may
|
||||||
|
be useful for moving TRX support to separated module / parser (if we
|
||||||
|
implement support for them at some point).
|
||||||
|
Finally parsing TRX at the end puts us in a better position as we have
|
||||||
|
better flash layout knowledge. It may be useful e.g. if it appears there
|
||||||
|
is more than 1 TRX partition.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
---
|
||||||
|
drivers/mtd/bcm47xxpart.c | 121 ++++++++++++++++++++++++++++------------------
|
||||||
|
1 file changed, 74 insertions(+), 47 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/mtd/bcm47xxpart.c
|
||||||
|
+++ b/drivers/mtd/bcm47xxpart.c
|
||||||
|
@@ -83,6 +83,67 @@ out_default:
|
||||||
|
return "rootfs";
|
||||||
|
}
|
||||||
|
|
||||||
|
+static int bcm47xxpart_parse_trx(struct mtd_info *master,
|
||||||
|
+ struct mtd_partition *trx,
|
||||||
|
+ struct mtd_partition *parts,
|
||||||
|
+ size_t parts_len)
|
||||||
|
+{
|
||||||
|
+ struct trx_header header;
|
||||||
|
+ size_t bytes_read;
|
||||||
|
+ int curr_part = 0;
|
||||||
|
+ int i, err;
|
||||||
|
+
|
||||||
|
+ if (parts_len < 3) {
|
||||||
|
+ pr_warn("No enough space to add TRX partitions!\n");
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ err = mtd_read(master, trx->offset, sizeof(header), &bytes_read,
|
||||||
|
+ (uint8_t *)&header);
|
||||||
|
+ if (err && !mtd_is_bitflip(err)) {
|
||||||
|
+ pr_err("mtd_read error while reading TRX header: %d\n", err);
|
||||||
|
+ return err;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ i = 0;
|
||||||
|
+
|
||||||
|
+ /* We have LZMA loader if offset[2] points to sth */
|
||||||
|
+ if (header.offset[2]) {
|
||||||
|
+ bcm47xxpart_add_part(&parts[curr_part++], "loader",
|
||||||
|
+ trx->offset + header.offset[i], 0);
|
||||||
|
+ i++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (header.offset[i]) {
|
||||||
|
+ bcm47xxpart_add_part(&parts[curr_part++], "linux",
|
||||||
|
+ trx->offset + header.offset[i], 0);
|
||||||
|
+ i++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (header.offset[i]) {
|
||||||
|
+ size_t offset = trx->offset + header.offset[i];
|
||||||
|
+ const char *name = bcm47xxpart_trx_data_part_name(master,
|
||||||
|
+ offset);
|
||||||
|
+
|
||||||
|
+ bcm47xxpart_add_part(&parts[curr_part++], name, offset, 0);
|
||||||
|
+ i++;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * Assume that every partition ends at the beginning of the one it is
|
||||||
|
+ * followed by.
|
||||||
|
+ */
|
||||||
|
+ for (i = 0; i < curr_part; i++) {
|
||||||
|
+ u64 next_part_offset = (i < curr_part - 1) ?
|
||||||
|
+ parts[i + 1].offset :
|
||||||
|
+ trx->offset + trx->size;
|
||||||
|
+
|
||||||
|
+ parts[i].size = next_part_offset - parts[i].offset;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return curr_part;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm47xxpart_parse(struct mtd_info *master,
|
||||||
|
const struct mtd_partition **pparts,
|
||||||
|
struct mtd_part_parser_data *data)
|
||||||
|
@@ -93,9 +154,7 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
size_t bytes_read;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t blocksize = master->erasesize;
|
||||||
|
- struct trx_header *trx;
|
||||||
|
int trx_part = -1;
|
||||||
|
- int last_trx_part = -1;
|
||||||
|
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
||||||
|
int err;
|
||||||
|
|
||||||
|
@@ -182,54 +241,14 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
|
||||||
|
/* TRX */
|
||||||
|
if (buf[0x000 / 4] == TRX_MAGIC) {
|
||||||
|
- if (BCM47XXPART_MAX_PARTS - curr_part < 4) {
|
||||||
|
- pr_warn("Not enough partitions left to register trx, scanning stopped!\n");
|
||||||
|
- break;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- trx = (struct trx_header *)buf;
|
||||||
|
+ struct trx_header *trx;
|
||||||
|
|
||||||
|
trx_part = curr_part;
|
||||||
|
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
|
||||||
|
offset, 0);
|
||||||
|
|
||||||
|
- i = 0;
|
||||||
|
- /* We have LZMA loader if offset[2] points to sth */
|
||||||
|
- if (trx->offset[2]) {
|
||||||
|
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||||
|
- "loader",
|
||||||
|
- offset + trx->offset[i],
|
||||||
|
- 0);
|
||||||
|
- i++;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- if (trx->offset[i]) {
|
||||||
|
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||||
|
- "linux",
|
||||||
|
- offset + trx->offset[i],
|
||||||
|
- 0);
|
||||||
|
- i++;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- /*
|
||||||
|
- * Pure rootfs size is known and can be calculated as:
|
||||||
|
- * trx->length - trx->offset[i]. We don't fill it as
|
||||||
|
- * we want to have jffs2 (overlay) in the same mtd.
|
||||||
|
- */
|
||||||
|
- if (trx->offset[i]) {
|
||||||
|
- const char *name;
|
||||||
|
-
|
||||||
|
- name = bcm47xxpart_trx_data_part_name(master, offset + trx->offset[i]);
|
||||||
|
- bcm47xxpart_add_part(&parts[curr_part++],
|
||||||
|
- name,
|
||||||
|
- offset + trx->offset[i],
|
||||||
|
- 0);
|
||||||
|
- i++;
|
||||||
|
- }
|
||||||
|
-
|
||||||
|
- last_trx_part = curr_part - 1;
|
||||||
|
-
|
||||||
|
/* Jump to the end of TRX */
|
||||||
|
+ trx = (struct trx_header *)buf;
|
||||||
|
offset = roundup(offset + trx->length, blocksize);
|
||||||
|
/* Next loop iteration will increase the offset */
|
||||||
|
offset -= blocksize;
|
||||||
|
@@ -307,9 +326,17 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
parts[i + 1].offset : master->size;
|
||||||
|
|
||||||
|
parts[i].size = next_part_offset - parts[i].offset;
|
||||||
|
- if (i == last_trx_part && trx_part >= 0)
|
||||||
|
- parts[trx_part].size = next_part_offset -
|
||||||
|
- parts[trx_part].offset;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ /* If there was TRX parse it now */
|
||||||
|
+ if (trx_part >= 0) {
|
||||||
|
+ int num_parts;
|
||||||
|
+
|
||||||
|
+ num_parts = bcm47xxpart_parse_trx(master, &parts[trx_part],
|
||||||
|
+ parts + curr_part,
|
||||||
|
+ BCM47XXPART_MAX_PARTS - curr_part);
|
||||||
|
+ if (num_parts > 0)
|
||||||
|
+ curr_part += num_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pparts = parts;
|
|
@ -0,0 +1,108 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Subject: [PATCH 2/2] mtd: bcm47xxpart: support layouts with multiple TRX
|
||||||
|
partitions
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
Some devices may have an extra TRX partition used as failsafe one. If
|
||||||
|
we detect such partition we should set a proper name for it and don't
|
||||||
|
parse it.
|
||||||
|
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
---
|
||||||
|
drivers/mtd/bcm47xxpart.c | 56 ++++++++++++++++++++++++++++++++++++++---------
|
||||||
|
1 file changed, 46 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/mtd/bcm47xxpart.c
|
||||||
|
+++ b/drivers/mtd/bcm47xxpart.c
|
||||||
|
@@ -9,6 +9,7 @@
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#include <linux/bcm47xx_nvram.h>
|
||||||
|
#include <linux/module.h>
|
||||||
|
#include <linux/kernel.h>
|
||||||
|
#include <linux/slab.h>
|
||||||
|
@@ -144,6 +145,30 @@ static int bcm47xxpart_parse_trx(struct
|
||||||
|
return curr_part;
|
||||||
|
}
|
||||||
|
|
||||||
|
+/**
|
||||||
|
+ * bcm47xxpart_bootpartition - gets index of TRX partition used by bootloader
|
||||||
|
+ *
|
||||||
|
+ * Some devices may have more than one TRX partition. In such case one of them
|
||||||
|
+ * is the main one and another a failsafe one. Bootloader may fallback to the
|
||||||
|
+ * failsafe firmware if it detects corruption of the main image.
|
||||||
|
+ *
|
||||||
|
+ * This function provides info about currently used TRX partition. It's the one
|
||||||
|
+ * containing kernel started by the bootloader.
|
||||||
|
+ */
|
||||||
|
+static int bcm47xxpart_bootpartition(void)
|
||||||
|
+{
|
||||||
|
+ char buf[4];
|
||||||
|
+ int bootpartition;
|
||||||
|
+
|
||||||
|
+ /* Check CFE environment variable */
|
||||||
|
+ if (bcm47xx_nvram_getenv("bootpartition", buf, sizeof(buf)) > 0) {
|
||||||
|
+ if (!kstrtoint(buf, 0, &bootpartition))
|
||||||
|
+ return bootpartition;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int bcm47xxpart_parse(struct mtd_info *master,
|
||||||
|
const struct mtd_partition **pparts,
|
||||||
|
struct mtd_part_parser_data *data)
|
||||||
|
@@ -154,7 +179,8 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
size_t bytes_read;
|
||||||
|
uint32_t offset;
|
||||||
|
uint32_t blocksize = master->erasesize;
|
||||||
|
- int trx_part = -1;
|
||||||
|
+ int trx_parts[2]; /* Array with indexes of TRX partitions */
|
||||||
|
+ int trx_num = 0; /* Number of found TRX partitions */
|
||||||
|
int possible_nvram_sizes[] = { 0x8000, 0xF000, 0x10000, };
|
||||||
|
int err;
|
||||||
|
|
||||||
|
@@ -243,7 +269,11 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
if (buf[0x000 / 4] == TRX_MAGIC) {
|
||||||
|
struct trx_header *trx;
|
||||||
|
|
||||||
|
- trx_part = curr_part;
|
||||||
|
+ if (trx_num >= ARRAY_SIZE(trx_parts))
|
||||||
|
+ pr_warn("No enough space to store another TRX found at 0x%X\n",
|
||||||
|
+ offset);
|
||||||
|
+ else
|
||||||
|
+ trx_parts[trx_num++] = curr_part;
|
||||||
|
bcm47xxpart_add_part(&parts[curr_part++], "firmware",
|
||||||
|
offset, 0);
|
||||||
|
|
||||||
|
@@ -329,14 +359,20 @@ static int bcm47xxpart_parse(struct mtd_
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If there was TRX parse it now */
|
||||||
|
- if (trx_part >= 0) {
|
||||||
|
- int num_parts;
|
||||||
|
+ for (i = 0; i < trx_num; i++) {
|
||||||
|
+ struct mtd_partition *trx = &parts[trx_parts[i]];
|
||||||
|
|
||||||
|
- num_parts = bcm47xxpart_parse_trx(master, &parts[trx_part],
|
||||||
|
- parts + curr_part,
|
||||||
|
- BCM47XXPART_MAX_PARTS - curr_part);
|
||||||
|
- if (num_parts > 0)
|
||||||
|
- curr_part += num_parts;
|
||||||
|
+ if (i == bcm47xxpart_bootpartition()) {
|
||||||
|
+ int num_parts;
|
||||||
|
+
|
||||||
|
+ num_parts = bcm47xxpart_parse_trx(master, trx,
|
||||||
|
+ parts + curr_part,
|
||||||
|
+ BCM47XXPART_MAX_PARTS - curr_part);
|
||||||
|
+ if (num_parts > 0)
|
||||||
|
+ curr_part += num_parts;
|
||||||
|
+ } else {
|
||||||
|
+ trx->name = "failsafe";
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
|
||||||
|
*pparts = parts;
|
|
@ -0,0 +1,21 @@
|
||||||
|
From: "L. D. Pinney" <ldpinney@gmail.com>
|
||||||
|
Date: Thu, 25 Aug 2016 13:07:56 -0500
|
||||||
|
Subject: [PATCH] mtd: spi-nor: add support for ESMT_f25l32qa and ESMT_f25l64qa
|
||||||
|
|
||||||
|
Add Support for the ESMT_F25L32QA and ESMT_F25L64QA
|
||||||
|
These are 4MB and 8MB SPI NOR Chips from Elite Semiconductor Memory Technology
|
||||||
|
|
||||||
|
Signed-off-by: L. D. Pinney <ldpinney@gmail.com>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/mtd/spi-nor/spi-nor.c
|
||||||
|
+++ b/drivers/mtd/spi-nor/spi-nor.c
|
||||||
|
@@ -821,6 +821,8 @@ static const struct flash_info spi_nor_i
|
||||||
|
|
||||||
|
/* ESMT */
|
||||||
|
{ "f25l32pa", INFO(0x8c2016, 0, 64 * 1024, 64, SECT_4K) },
|
||||||
|
+ { "f25l32qa", INFO(0x8c4116, 0, 64 * 1024, 64, SECT_4K) },
|
||||||
|
+ { "f25l64qa", INFO(0x8c4117, 0, 64 * 1024, 128, SECT_4K) },
|
||||||
|
|
||||||
|
/* Everspin */
|
||||||
|
{ "mr25h256", CAT25_INFO( 32 * 1024, 1, 256, 2, SPI_NOR_NO_ERASE | SPI_NOR_NO_FR) },
|
|
@ -0,0 +1,92 @@
|
||||||
|
From: =?UTF-8?q?Rafa=C5=82=20Mi=C5=82ecki?= <rafal@milecki.pl>
|
||||||
|
Subject: [PATCH] Revert "bcma: init serial console directly from ChipCommon
|
||||||
|
code"
|
||||||
|
MIME-Version: 1.0
|
||||||
|
Content-Type: text/plain; charset=UTF-8
|
||||||
|
Content-Transfer-Encoding: 8bit
|
||||||
|
|
||||||
|
This reverts commit 4c81acab3816 ("bcma: init serial console directly
|
||||||
|
from ChipCommon code") as it broke IRQ assignment. Getting IRQ with
|
||||||
|
bcma_core_irq helper on SoC requires MIPS core to be set. It happens
|
||||||
|
*after* ChipCommon initialization so we can't do this so early.
|
||||||
|
|
||||||
|
This fixes a user reported regression. It wasn't critical as serial was
|
||||||
|
still somehow working but lack of IRQs was making in unreliable.
|
||||||
|
|
||||||
|
Fixes: 4c81acab3816 ("bcma: init serial console directly from ChipCommon code")
|
||||||
|
Reported-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Cc: stable@vger.kernel.org # 4.6+
|
||||||
|
Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
|
||||||
|
---
|
||||||
|
drivers/bcma/bcma_private.h | 3 +++
|
||||||
|
drivers/bcma/driver_chipcommon.c | 11 +++--------
|
||||||
|
drivers/bcma/driver_mips.c | 3 +++
|
||||||
|
3 files changed, 9 insertions(+), 8 deletions(-)
|
||||||
|
|
||||||
|
--- a/drivers/bcma/bcma_private.h
|
||||||
|
+++ b/drivers/bcma/bcma_private.h
|
||||||
|
@@ -45,6 +45,9 @@ int bcma_sprom_get(struct bcma_bus *bus)
|
||||||
|
void bcma_core_chipcommon_early_init(struct bcma_drv_cc *cc);
|
||||||
|
void bcma_core_chipcommon_init(struct bcma_drv_cc *cc);
|
||||||
|
void bcma_chipco_bcm4331_ext_pa_lines_ctl(struct bcma_drv_cc *cc, bool enable);
|
||||||
|
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||||
|
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||||
|
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||||
|
|
||||||
|
/* driver_chipcommon_b.c */
|
||||||
|
int bcma_core_chipcommon_b_init(struct bcma_drv_cc_b *ccb);
|
||||||
|
--- a/drivers/bcma/driver_chipcommon.c
|
||||||
|
+++ b/drivers/bcma/driver_chipcommon.c
|
||||||
|
@@ -15,8 +15,6 @@
|
||||||
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/bcma/bcma.h>
|
||||||
|
|
||||||
|
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc);
|
||||||
|
-
|
||||||
|
static inline u32 bcma_cc_write32_masked(struct bcma_drv_cc *cc, u16 offset,
|
||||||
|
u32 mask, u32 value)
|
||||||
|
{
|
||||||
|
@@ -186,9 +184,6 @@ void bcma_core_chipcommon_early_init(str
|
||||||
|
if (cc->capabilities & BCMA_CC_CAP_PMU)
|
||||||
|
bcma_pmu_early_init(cc);
|
||||||
|
|
||||||
|
- if (IS_BUILTIN(CONFIG_BCM47XX) && bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||||
|
- bcma_chipco_serial_init(cc);
|
||||||
|
-
|
||||||
|
if (bus->hosttype == BCMA_HOSTTYPE_SOC)
|
||||||
|
bcma_core_chipcommon_flash_detect(cc);
|
||||||
|
|
||||||
|
@@ -378,9 +373,9 @@ u32 bcma_chipco_gpio_pulldown(struct bcm
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
-static void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
||||||
|
+#ifdef CONFIG_BCMA_DRIVER_MIPS
|
||||||
|
+void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
|
||||||
|
{
|
||||||
|
-#if IS_BUILTIN(CONFIG_BCM47XX)
|
||||||
|
unsigned int irq;
|
||||||
|
u32 baud_base;
|
||||||
|
u32 i;
|
||||||
|
@@ -422,5 +417,5 @@ static void bcma_chipco_serial_init(stru
|
||||||
|
ports[i].baud_base = baud_base;
|
||||||
|
ports[i].reg_shift = 0;
|
||||||
|
}
|
||||||
|
-#endif /* CONFIG_BCM47XX */
|
||||||
|
}
|
||||||
|
+#endif /* CONFIG_BCMA_DRIVER_MIPS */
|
||||||
|
--- a/drivers/bcma/driver_mips.c
|
||||||
|
+++ b/drivers/bcma/driver_mips.c
|
||||||
|
@@ -278,9 +278,12 @@ static void bcma_core_mips_nvram_init(st
|
||||||
|
|
||||||
|
void bcma_core_mips_early_init(struct bcma_drv_mips *mcore)
|
||||||
|
{
|
||||||
|
+ struct bcma_bus *bus = mcore->core->bus;
|
||||||
|
+
|
||||||
|
if (mcore->early_setup_done)
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ bcma_chipco_serial_init(&bus->drv_cc);
|
||||||
|
bcma_core_mips_nvram_init(mcore);
|
||||||
|
|
||||||
|
mcore->early_setup_done = true;
|
|
@ -0,0 +1,71 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Date: Wed, 30 Nov 2016 11:31:03 +0100
|
||||||
|
Subject: [PATCH] net: phy: at803x: add support for AT8032
|
||||||
|
|
||||||
|
Like AT8030, this PHY needs the GPIO reset workaround
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/drivers/net/phy/at803x.c
|
||||||
|
+++ b/drivers/net/phy/at803x.c
|
||||||
|
@@ -62,6 +62,7 @@
|
||||||
|
|
||||||
|
#define ATH8030_PHY_ID 0x004dd076
|
||||||
|
#define ATH8031_PHY_ID 0x004dd074
|
||||||
|
+#define ATH8032_PHY_ID 0x004dd023
|
||||||
|
#define ATH8035_PHY_ID 0x004dd072
|
||||||
|
|
||||||
|
MODULE_DESCRIPTION("Atheros 803x PHY driver");
|
||||||
|
@@ -259,7 +260,8 @@ static int at803x_probe(struct phy_devic
|
||||||
|
if (!priv)
|
||||||
|
return -ENOMEM;
|
||||||
|
|
||||||
|
- if (phydev->drv->phy_id != ATH8030_PHY_ID)
|
||||||
|
+ if (phydev->drv->phy_id != ATH8030_PHY_ID &&
|
||||||
|
+ phydev->drv->phy_id != ATH8032_PHY_ID)
|
||||||
|
goto does_not_require_reset_workaround;
|
||||||
|
|
||||||
|
gpiod_reset = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_LOW);
|
||||||
|
@@ -335,7 +337,7 @@ static void at803x_link_change_notify(st
|
||||||
|
struct at803x_priv *priv = phydev->priv;
|
||||||
|
|
||||||
|
/*
|
||||||
|
- * Conduct a hardware reset for AT8030 every time a link loss is
|
||||||
|
+ * Conduct a hardware reset for AT8030/2 every time a link loss is
|
||||||
|
* signalled. This is necessary to circumvent a hardware bug that
|
||||||
|
* occurs when the cable is unplugged while TX packets are pending
|
||||||
|
* in the FIFO. In such cases, the FIFO enters an error mode it
|
||||||
|
@@ -447,6 +449,24 @@ static struct phy_driver at803x_driver[]
|
||||||
|
.aneg_done = at803x_aneg_done,
|
||||||
|
.ack_interrupt = &at803x_ack_interrupt,
|
||||||
|
.config_intr = &at803x_config_intr,
|
||||||
|
+}, {
|
||||||
|
+ /* ATHEROS 8032 */
|
||||||
|
+ .phy_id = ATH8032_PHY_ID,
|
||||||
|
+ .name = "Atheros 8032 ethernet",
|
||||||
|
+ .phy_id_mask = 0xffffffef,
|
||||||
|
+ .probe = at803x_probe,
|
||||||
|
+ .config_init = at803x_config_init,
|
||||||
|
+ .link_change_notify = at803x_link_change_notify,
|
||||||
|
+ .set_wol = at803x_set_wol,
|
||||||
|
+ .get_wol = at803x_get_wol,
|
||||||
|
+ .suspend = at803x_suspend,
|
||||||
|
+ .resume = at803x_resume,
|
||||||
|
+ .features = PHY_BASIC_FEATURES,
|
||||||
|
+ .flags = PHY_HAS_INTERRUPT,
|
||||||
|
+ .config_aneg = genphy_config_aneg,
|
||||||
|
+ .read_status = genphy_read_status,
|
||||||
|
+ .ack_interrupt = at803x_ack_interrupt,
|
||||||
|
+ .config_intr = at803x_config_intr,
|
||||||
|
} };
|
||||||
|
|
||||||
|
module_phy_driver(at803x_driver);
|
||||||
|
@@ -454,6 +474,7 @@ module_phy_driver(at803x_driver);
|
||||||
|
static struct mdio_device_id __maybe_unused atheros_tbl[] = {
|
||||||
|
{ ATH8030_PHY_ID, 0xffffffef },
|
||||||
|
{ ATH8031_PHY_ID, 0xffffffef },
|
||||||
|
+ { ATH8032_PHY_ID, 0xffffffef },
|
||||||
|
{ ATH8035_PHY_ID, 0xffffffef },
|
||||||
|
{ }
|
||||||
|
};
|
|
@ -0,0 +1,11 @@
|
||||||
|
--- a/scripts/setlocalversion
|
||||||
|
+++ b/scripts/setlocalversion
|
||||||
|
@@ -165,7 +165,7 @@ else
|
||||||
|
# annotated or signed tagged state (as git describe only
|
||||||
|
# looks at signed or annotated tags - git tag -a/-s) and
|
||||||
|
# LOCALVERSION= is not specified
|
||||||
|
- if test "${LOCALVERSION+set}" != "set"; then
|
||||||
|
+ if test "${CONFIG_LOCALVERSION+set}" != "set"; then
|
||||||
|
scm=$(scm_version --short)
|
||||||
|
res="$res${scm:++}"
|
||||||
|
fi
|
|
@ -0,0 +1,18 @@
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -636,12 +636,12 @@ KBUILD_CFLAGS += $(call cc-option,-fdata
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||||
|
-KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,)
|
||||||
|
+KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) $(EXTRA_OPTIMIZATION)
|
||||||
|
else
|
||||||
|
ifdef CONFIG_PROFILE_ALL_BRANCHES
|
||||||
|
-KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,)
|
||||||
|
+KBUILD_CFLAGS += -O2 $(call cc-disable-warning,maybe-uninitialized,) $(EXTRA_OPTIMIZATION)
|
||||||
|
else
|
||||||
|
-KBUILD_CFLAGS += -O2
|
||||||
|
+KBUILD_CFLAGS += -O2 -fno-reorder-blocks -fno-tree-ch $(EXTRA_OPTIMIZATION)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -407,7 +407,7 @@ KBUILD_CFLAGS_KERNEL :=
|
||||||
|
KBUILD_AFLAGS := -D__ASSEMBLY__ $(call cc-option,-fno-PIE)
|
||||||
|
KBUILD_AFLAGS_MODULE := -DMODULE
|
||||||
|
KBUILD_CFLAGS_MODULE := -DMODULE
|
||||||
|
-KBUILD_LDFLAGS_MODULE := -T $(srctree)/scripts/module-common.lds
|
||||||
|
+KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
|
||||||
|
|
||||||
|
# Read KERNELRELEASE from include/config/kernel.release (if it exists)
|
||||||
|
KERNELRELEASE = $(shell cat include/config/kernel.release 2> /dev/null)
|
|
@ -0,0 +1,106 @@
|
||||||
|
--- a/scripts/kallsyms.c
|
||||||
|
+++ b/scripts/kallsyms.c
|
||||||
|
@@ -61,6 +61,7 @@ static struct addr_range percpu_range =
|
||||||
|
static struct sym_entry *table;
|
||||||
|
static unsigned int table_size, table_cnt;
|
||||||
|
static int all_symbols = 0;
|
||||||
|
+static int uncompressed = 0;
|
||||||
|
static int absolute_percpu = 0;
|
||||||
|
static char symbol_prefix_char = '\0';
|
||||||
|
static int base_relative = 0;
|
||||||
|
@@ -446,6 +447,9 @@ static void write_src(void)
|
||||||
|
|
||||||
|
free(markers);
|
||||||
|
|
||||||
|
+ if (uncompressed)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
output_label("kallsyms_token_table");
|
||||||
|
off = 0;
|
||||||
|
for (i = 0; i < 256; i++) {
|
||||||
|
@@ -504,6 +508,9 @@ static void *find_token(unsigned char *s
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
+ if (uncompressed)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
for (i = 0; i < len - 1; i++) {
|
||||||
|
if (str[i] == token[0] && str[i+1] == token[1])
|
||||||
|
return &str[i];
|
||||||
|
@@ -576,6 +583,9 @@ static void optimize_result(void)
|
||||||
|
{
|
||||||
|
int i, best;
|
||||||
|
|
||||||
|
+ if (uncompressed)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
/* using the '\0' symbol last allows compress_symbols to use standard
|
||||||
|
* fast string functions */
|
||||||
|
for (i = 255; i >= 0; i--) {
|
||||||
|
@@ -764,6 +774,8 @@ int main(int argc, char **argv)
|
||||||
|
symbol_prefix_char = *p;
|
||||||
|
} else if (strcmp(argv[i], "--base-relative") == 0)
|
||||||
|
base_relative = 1;
|
||||||
|
+ else if (strcmp(argv[i], "--uncompressed") == 0)
|
||||||
|
+ uncompressed = 1;
|
||||||
|
else
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
--- a/init/Kconfig
|
||||||
|
+++ b/init/Kconfig
|
||||||
|
@@ -1370,6 +1370,17 @@ config SYSCTL_ARCH_UNALIGN_ALLOW
|
||||||
|
the unaligned access emulation.
|
||||||
|
see arch/parisc/kernel/unaligned.c for reference
|
||||||
|
|
||||||
|
+config KALLSYMS_UNCOMPRESSED
|
||||||
|
+ bool "Keep kallsyms uncompressed"
|
||||||
|
+ depends on KALLSYMS
|
||||||
|
+ help
|
||||||
|
+ Normally kallsyms contains compressed symbols (using a token table),
|
||||||
|
+ reducing the uncompressed kernel image size. Keeping the symbol table
|
||||||
|
+ uncompressed significantly improves the size of this part in compressed
|
||||||
|
+ kernel images.
|
||||||
|
+
|
||||||
|
+ Say N unless you need compressed kernel images to be small.
|
||||||
|
+
|
||||||
|
config HAVE_PCSPKR_PLATFORM
|
||||||
|
bool
|
||||||
|
|
||||||
|
--- a/scripts/link-vmlinux.sh
|
||||||
|
+++ b/scripts/link-vmlinux.sh
|
||||||
|
@@ -136,6 +136,10 @@ kallsyms()
|
||||||
|
kallsymopt="${kallsymopt} --base-relative"
|
||||||
|
fi
|
||||||
|
|
||||||
|
+ if [ -n "${CONFIG_KALLSYMS_UNCOMPRESSED}" ]; then
|
||||||
|
+ kallsymopt="${kallsymopt} --uncompressed"
|
||||||
|
+ fi
|
||||||
|
+
|
||||||
|
local aflags="${KBUILD_AFLAGS} ${KBUILD_AFLAGS_KERNEL} \
|
||||||
|
${NOSTDINC_FLAGS} ${LINUXINCLUDE} ${KBUILD_CPPFLAGS}"
|
||||||
|
|
||||||
|
--- a/kernel/kallsyms.c
|
||||||
|
+++ b/kernel/kallsyms.c
|
||||||
|
@@ -113,6 +113,11 @@ static unsigned int kallsyms_expand_symb
|
||||||
|
* For every byte on the compressed symbol data, copy the table
|
||||||
|
* entry for that byte.
|
||||||
|
*/
|
||||||
|
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||||
|
+ memcpy(result, data + 1, len - 1);
|
||||||
|
+ result += len - 1;
|
||||||
|
+ len = 0;
|
||||||
|
+#endif
|
||||||
|
while (len) {
|
||||||
|
tptr = &kallsyms_token_table[kallsyms_token_index[*data]];
|
||||||
|
data++;
|
||||||
|
@@ -145,6 +150,9 @@ tail:
|
||||||
|
*/
|
||||||
|
static char kallsyms_get_symbol_type(unsigned int off)
|
||||||
|
{
|
||||||
|
+#ifdef CONFIG_KALLSYMS_UNCOMPRESSED
|
||||||
|
+ return kallsyms_names[off + 1];
|
||||||
|
+#endif
|
||||||
|
/*
|
||||||
|
* Get just the first code, look it up in the token table,
|
||||||
|
* and return the first char from this token.
|
|
@ -0,0 +1,195 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
Subject: [PATCH] build: add a hack for removing non-essential module info
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
--- a/include/linux/module.h
|
||||||
|
+++ b/include/linux/module.h
|
||||||
|
@@ -159,6 +159,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)
|
||||||
|
@@ -202,12 +203,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 const typeof(name) __mod_##type##__##name##_device_table \
|
||||||
|
@@ -234,7 +235,9 @@ extern const typeof(name) __mod_##type##
|
||||||
|
*/
|
||||||
|
|
||||||
|
#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 = { \
|
||||||
|
@@ -256,7 +259,7 @@ extern const typeof(name) __mod_##type##
|
||||||
|
/* 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
|
||||||
|
@@ -16,6 +16,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)[] \
|
||||||
|
@@ -23,8 +33,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)
|
||||||
|
@@ -32,7 +41,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
|
||||||
|
@@ -2106,6 +2106,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
|
||||||
|
@@ -2945,9 +2945,11 @@ static struct module *setup_load_info(st
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
||||||
|
@@ -2968,6 +2970,7 @@ static int check_modinfo(struct module *
|
||||||
|
mod->name);
|
||||||
|
add_taint_module(mod, TAINT_OOT_MODULE, LOCKDEP_STILL_OK);
|
||||||
|
}
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
if (get_modinfo(info, "staging")) {
|
||||||
|
add_taint_module(mod, TAINT_CRAP, LOCKDEP_STILL_OK);
|
||||||
|
--- a/scripts/mod/modpost.c
|
||||||
|
+++ b/scripts/mod/modpost.c
|
||||||
|
@@ -1964,7 +1964,9 @@ static void read_symbols(char *modname)
|
||||||
|
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) ||
|
||||||
|
(is_vmlinux(modname) && vmlinux_section_warnings))
|
||||||
|
@@ -2108,7 +2110,9 @@ static void add_header(struct buffer *b,
|
||||||
|
buf_printf(b, "#include <linux/vermagic.h>\n");
|
||||||
|
buf_printf(b, "#include <linux/compiler.h>\n");
|
||||||
|
buf_printf(b, "\n");
|
||||||
|
+#ifndef CONFIG_MODULE_STRIPPED
|
||||||
|
buf_printf(b, "MODULE_INFO(vermagic, VERMAGIC_STRING);\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");
|
||||||
|
@@ -2125,16 +2129,20 @@ 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
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_staging_flag(struct buffer *b, const char *name)
|
||||||
|
{
|
||||||
|
+#ifndef CONFIG_MODULE_STRIPPED
|
||||||
|
static const char *staging_dir = "drivers/staging";
|
||||||
|
|
||||||
|
if (strncmp(staging_dir, name, strlen(staging_dir)) == 0)
|
||||||
|
buf_printf(b, "\nMODULE_INFO(staging, \"Y\");\n");
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/* In kernel, this size is defined in linux/module.h;
|
||||||
|
@@ -2238,11 +2246,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)
|
||||||
|
@@ -2476,7 +2486,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);
|
|
@ -0,0 +1,33 @@
|
||||||
|
--- a/lib/vsprintf.c
|
||||||
|
+++ b/lib/vsprintf.c
|
||||||
|
@@ -669,8 +669,10 @@ char *symbol_string(char *buf, char *end
|
||||||
|
struct printf_spec spec, const char *fmt)
|
||||||
|
{
|
||||||
|
unsigned long value;
|
||||||
|
-#ifdef CONFIG_KALLSYMS
|
||||||
|
char sym[KSYM_SYMBOL_LEN];
|
||||||
|
+#ifndef CONFIG_KALLSYMS
|
||||||
|
+ struct module *mod;
|
||||||
|
+ int len;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (fmt[1] == 'R')
|
||||||
|
@@ -684,11 +686,15 @@ char *symbol_string(char *buf, char *end
|
||||||
|
sprint_symbol(sym, value);
|
||||||
|
else
|
||||||
|
sprint_symbol_no_offset(sym, value);
|
||||||
|
-
|
||||||
|
- return string(buf, end, sym, spec);
|
||||||
|
#else
|
||||||
|
- return special_hex_number(buf, end, value, sizeof(void *));
|
||||||
|
+ len = snprintf(sym, sizeof(sym), "0x%lx", value);
|
||||||
|
+
|
||||||
|
+ mod = __module_address(value);
|
||||||
|
+ if (mod)
|
||||||
|
+ snprintf(sym + len, sizeof(sym) - len, " [%s@%p+0x%x]",
|
||||||
|
+ mod->name, mod->module_core, mod->core_size);
|
||||||
|
#endif
|
||||||
|
+ return string(buf, end, sym, spec);
|
||||||
|
}
|
||||||
|
|
||||||
|
static noinline_for_stack
|
|
@ -0,0 +1,18 @@
|
||||||
|
Disable MIPS VDSO until the cache issues have been sorted out.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
|
--- a/arch/mips/vdso/Makefile
|
||||||
|
+++ b/arch/mips/vdso/Makefile
|
||||||
|
@@ -28,9 +28,9 @@ aflags-vdso := $(ccflags-vdso) \
|
||||||
|
ifndef CONFIG_CPU_MIPSR6
|
||||||
|
ifeq ($(call ld-ifversion, -lt, 225000000, y),y)
|
||||||
|
$(warning MIPS VDSO requires binutils >= 2.25)
|
||||||
|
- obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
|
||||||
|
- ccflags-vdso += -DDISABLE_MIPS_VDSO
|
||||||
|
endif
|
||||||
|
+ obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
|
||||||
|
+ ccflags-vdso += -DDISABLE_MIPS_VDSO
|
||||||
|
endif
|
||||||
|
|
||||||
|
# VDSO linker flags.
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,51 @@
|
||||||
|
--- a/tools/include/tools/be_byteshift.h
|
||||||
|
+++ b/tools/include/tools/be_byteshift.h
|
||||||
|
@@ -1,6 +1,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
|
||||||
|
@@ -1,6 +1,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
|
|
@ -0,0 +1,11 @@
|
||||||
|
--- a/include/uapi/linux/spi/spidev.h
|
||||||
|
+++ b/include/uapi/linux/spi/spidev.h
|
||||||
|
@@ -111,7 +111,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)])
|
||||||
|
|
|
@ -0,0 +1,403 @@
|
||||||
|
From: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
|
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>
|
||||||
|
---
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/vmlinux.lds.S
|
||||||
|
+++ b/arch/mips/kernel/vmlinux.lds.S
|
||||||
|
@@ -71,7 +71,7 @@ SECTIONS
|
||||||
|
/* Exception table for data bus errors */
|
||||||
|
__dbe_table : {
|
||||||
|
__start___dbe_table = .;
|
||||||
|
- *(__dbe_table)
|
||||||
|
+ KEEP(*(__dbe_table))
|
||||||
|
__stop___dbe_table = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -121,7 +121,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 = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
--- a/include/asm-generic/vmlinux.lds.h
|
||||||
|
+++ b/include/asm-generic/vmlinux.lds.h
|
||||||
|
@@ -114,7 +114,7 @@
|
||||||
|
#ifdef CONFIG_KPROBES
|
||||||
|
#define KPROBE_BLACKLIST() . = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start_kprobe_blacklist) = .; \
|
||||||
|
- *(_kprobe_blacklist) \
|
||||||
|
+ KEEP(*(_kprobe_blacklist)) \
|
||||||
|
VMLINUX_SYMBOL(__stop_kprobe_blacklist) = .;
|
||||||
|
#else
|
||||||
|
#define KPROBE_BLACKLIST()
|
||||||
|
@@ -123,10 +123,10 @@
|
||||||
|
#ifdef CONFIG_EVENT_TRACING
|
||||||
|
#define FTRACE_EVENTS() . = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start_ftrace_events) = .; \
|
||||||
|
- *(_ftrace_events) \
|
||||||
|
+ KEEP(*(_ftrace_events)) \
|
||||||
|
VMLINUX_SYMBOL(__stop_ftrace_events) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_ftrace_enum_maps) = .; \
|
||||||
|
- *(_ftrace_enum_map) \
|
||||||
|
+ KEEP(*(_ftrace_enum_map)) \
|
||||||
|
VMLINUX_SYMBOL(__stop_ftrace_enum_maps) = .;
|
||||||
|
#else
|
||||||
|
#define FTRACE_EVENTS()
|
||||||
|
@@ -147,7 +147,7 @@
|
||||||
|
#ifdef CONFIG_FTRACE_SYSCALLS
|
||||||
|
#define TRACE_SYSCALLS() . = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start_syscalls_metadata) = .; \
|
||||||
|
- *(__syscalls_metadata) \
|
||||||
|
+ KEEP(*(__syscalls_metadata)) \
|
||||||
|
VMLINUX_SYMBOL(__stop_syscalls_metadata) = .;
|
||||||
|
#else
|
||||||
|
#define TRACE_SYSCALLS()
|
||||||
|
@@ -169,8 +169,8 @@
|
||||||
|
#define _OF_TABLE_1(name) \
|
||||||
|
. = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__##name##_of_table) = .; \
|
||||||
|
- *(__##name##_of_table) \
|
||||||
|
- *(__##name##_of_table_end)
|
||||||
|
+ KEEP(*(__##name##_of_table)) \
|
||||||
|
+ KEEP(*(__##name##_of_table_end))
|
||||||
|
|
||||||
|
#define CLKSRC_OF_TABLES() OF_TABLE(CONFIG_CLKSRC_OF, clksrc)
|
||||||
|
#define IRQCHIP_OF_MATCH_TABLE() OF_TABLE(CONFIG_IRQCHIP, irqchip)
|
||||||
|
@@ -193,7 +193,7 @@
|
||||||
|
#define KERNEL_DTB() \
|
||||||
|
STRUCT_ALIGN(); \
|
||||||
|
VMLINUX_SYMBOL(__dtb_start) = .; \
|
||||||
|
- *(.dtb.init.rodata) \
|
||||||
|
+ KEEP(*(.dtb.init.rodata)) \
|
||||||
|
VMLINUX_SYMBOL(__dtb_end) = .;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -214,16 +214,17 @@
|
||||||
|
/* implement dynamic printk debug */ \
|
||||||
|
. = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start___jump_table) = .; \
|
||||||
|
- *(__jump_table) \
|
||||||
|
+ KEEP(*(__jump_table)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___jump_table) = .; \
|
||||||
|
. = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__start___verbose) = .; \
|
||||||
|
- *(__verbose) \
|
||||||
|
+ KEEP(*(__verbose)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___verbose) = .; \
|
||||||
|
LIKELY_PROFILE() \
|
||||||
|
BRANCH_PROFILE() \
|
||||||
|
TRACE_PRINTKS() \
|
||||||
|
- TRACEPOINT_STR()
|
||||||
|
+ TRACEPOINT_STR() \
|
||||||
|
+ *(.data.[a-zA-Z_]*)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Data section helpers
|
||||||
|
@@ -291,35 +292,35 @@
|
||||||
|
/* PCI quirks */ \
|
||||||
|
.pci_fixup : AT(ADDR(.pci_fixup) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_early) = .; \
|
||||||
|
- *(.pci_fixup_early) \
|
||||||
|
+ KEEP(*(.pci_fixup_early)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_early) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_header) = .; \
|
||||||
|
- *(.pci_fixup_header) \
|
||||||
|
+ KEEP(*(.pci_fixup_header)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_header) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_final) = .; \
|
||||||
|
- *(.pci_fixup_final) \
|
||||||
|
+ KEEP(*(.pci_fixup_final)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_final) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_enable) = .; \
|
||||||
|
- *(.pci_fixup_enable) \
|
||||||
|
+ KEEP(*(.pci_fixup_enable)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_enable) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_resume) = .; \
|
||||||
|
- *(.pci_fixup_resume) \
|
||||||
|
+ KEEP(*(.pci_fixup_resume)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_resume) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_resume_early) = .; \
|
||||||
|
- *(.pci_fixup_resume_early) \
|
||||||
|
+ KEEP(*(.pci_fixup_resume_early)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_resume_early) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_suspend) = .; \
|
||||||
|
- *(.pci_fixup_suspend) \
|
||||||
|
+ KEEP(*(.pci_fixup_suspend)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_suspend) = .; \
|
||||||
|
VMLINUX_SYMBOL(__start_pci_fixups_suspend_late) = .; \
|
||||||
|
- *(.pci_fixup_suspend_late) \
|
||||||
|
+ KEEP(*(.pci_fixup_suspend_late)) \
|
||||||
|
VMLINUX_SYMBOL(__end_pci_fixups_suspend_late) = .; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Built-in firmware blobs */ \
|
||||||
|
.builtin_fw : AT(ADDR(.builtin_fw) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start_builtin_fw) = .; \
|
||||||
|
- *(.builtin_fw) \
|
||||||
|
+ KEEP(*(.builtin_fw)) \
|
||||||
|
VMLINUX_SYMBOL(__end_builtin_fw) = .; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
@@ -397,7 +398,7 @@
|
||||||
|
\
|
||||||
|
/* Kernel symbol table: strings */ \
|
||||||
|
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||||
|
- KEEP(*(__ksymtab_strings)) \
|
||||||
|
+ *(__ksymtab_strings) \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* __*init sections */ \
|
||||||
|
@@ -410,14 +411,14 @@
|
||||||
|
/* Built-in module parameters. */ \
|
||||||
|
__param : AT(ADDR(__param) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___param) = .; \
|
||||||
|
- *(__param) \
|
||||||
|
+ KEEP(*(__param)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___param) = .; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Built-in module versions. */ \
|
||||||
|
__modver : AT(ADDR(__modver) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___modver) = .; \
|
||||||
|
- *(__modver) \
|
||||||
|
+ KEEP(*(__modver)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___modver) = .; \
|
||||||
|
. = ALIGN((align)); \
|
||||||
|
VMLINUX_SYMBOL(__end_rodata) = .; \
|
||||||
|
@@ -482,7 +483,7 @@
|
||||||
|
#define ENTRY_TEXT \
|
||||||
|
ALIGN_FUNCTION(); \
|
||||||
|
VMLINUX_SYMBOL(__entry_text_start) = .; \
|
||||||
|
- *(.entry.text) \
|
||||||
|
+ KEEP(*(.entry.text)) \
|
||||||
|
VMLINUX_SYMBOL(__entry_text_end) = .;
|
||||||
|
|
||||||
|
#if defined(CONFIG_FUNCTION_GRAPH_TRACER) || defined(CONFIG_KASAN)
|
||||||
|
@@ -520,7 +521,7 @@
|
||||||
|
. = ALIGN(align); \
|
||||||
|
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___ex_table) = .; \
|
||||||
|
- *(__ex_table) \
|
||||||
|
+ KEEP(*(__ex_table)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___ex_table) = .; \
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -536,9 +537,9 @@
|
||||||
|
#ifdef CONFIG_CONSTRUCTORS
|
||||||
|
#define KERNEL_CTORS() . = ALIGN(8); \
|
||||||
|
VMLINUX_SYMBOL(__ctors_start) = .; \
|
||||||
|
- *(.ctors) \
|
||||||
|
+ KEEP(*(.ctors)) \
|
||||||
|
*(SORT(.init_array.*)) \
|
||||||
|
- *(.init_array) \
|
||||||
|
+ KEEP(*(.init_array)) \
|
||||||
|
VMLINUX_SYMBOL(__ctors_end) = .;
|
||||||
|
#else
|
||||||
|
#define KERNEL_CTORS()
|
||||||
|
@@ -595,7 +596,7 @@
|
||||||
|
#define SBSS(sbss_align) \
|
||||||
|
. = ALIGN(sbss_align); \
|
||||||
|
.sbss : AT(ADDR(.sbss) - LOAD_OFFSET) { \
|
||||||
|
- *(.sbss) \
|
||||||
|
+ *(.sbss .sbss.*) \
|
||||||
|
*(.scommon) \
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -662,7 +663,7 @@
|
||||||
|
. = ALIGN(8); \
|
||||||
|
__bug_table : AT(ADDR(__bug_table) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___bug_table) = .; \
|
||||||
|
- *(__bug_table) \
|
||||||
|
+ KEEP(*(__bug_table)) \
|
||||||
|
VMLINUX_SYMBOL(__stop___bug_table) = .; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
@@ -674,7 +675,7 @@
|
||||||
|
. = ALIGN(4); \
|
||||||
|
.tracedata : AT(ADDR(.tracedata) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__tracedata_start) = .; \
|
||||||
|
- *(.tracedata) \
|
||||||
|
+ KEEP(*(.tracedata)) \
|
||||||
|
VMLINUX_SYMBOL(__tracedata_end) = .; \
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
@@ -691,7 +692,7 @@
|
||||||
|
#define INIT_SETUP(initsetup_align) \
|
||||||
|
. = ALIGN(initsetup_align); \
|
||||||
|
VMLINUX_SYMBOL(__setup_start) = .; \
|
||||||
|
- *(.init.setup) \
|
||||||
|
+ KEEP(*(.init.setup)) \
|
||||||
|
VMLINUX_SYMBOL(__setup_end) = .;
|
||||||
|
|
||||||
|
#define INIT_CALLS_LEVEL(level) \
|
||||||
|
--- a/arch/arm/kernel/vmlinux.lds.S
|
||||||
|
+++ b/arch/arm/kernel/vmlinux.lds.S
|
||||||
|
@@ -17,7 +17,7 @@
|
||||||
|
#define PROC_INFO \
|
||||||
|
. = ALIGN(4); \
|
||||||
|
VMLINUX_SYMBOL(__proc_info_begin) = .; \
|
||||||
|
- *(.proc.info.init) \
|
||||||
|
+ KEEP(*(.proc.info.init)) \
|
||||||
|
VMLINUX_SYMBOL(__proc_info_end) = .;
|
||||||
|
|
||||||
|
#define HYPERVISOR_TEXT \
|
||||||
|
@@ -28,11 +28,11 @@
|
||||||
|
#define IDMAP_TEXT \
|
||||||
|
ALIGN_FUNCTION(); \
|
||||||
|
VMLINUX_SYMBOL(__idmap_text_start) = .; \
|
||||||
|
- *(.idmap.text) \
|
||||||
|
+ KEEP(*(.idmap.text)) \
|
||||||
|
VMLINUX_SYMBOL(__idmap_text_end) = .; \
|
||||||
|
. = ALIGN(PAGE_SIZE); \
|
||||||
|
VMLINUX_SYMBOL(__hyp_idmap_text_start) = .; \
|
||||||
|
- *(.hyp.idmap.text) \
|
||||||
|
+ KEEP(*(.hyp.idmap.text)) \
|
||||||
|
VMLINUX_SYMBOL(__hyp_idmap_text_end) = .;
|
||||||
|
|
||||||
|
#ifdef CONFIG_HOTPLUG_CPU
|
||||||
|
@@ -105,7 +105,7 @@ SECTIONS
|
||||||
|
_stext = .; /* Text and read-only data */
|
||||||
|
IDMAP_TEXT
|
||||||
|
__exception_text_start = .;
|
||||||
|
- *(.exception.text)
|
||||||
|
+ KEEP(*(.exception.text))
|
||||||
|
__exception_text_end = .;
|
||||||
|
IRQENTRY_TEXT
|
||||||
|
SOFTIRQENTRY_TEXT
|
||||||
|
@@ -134,7 +134,7 @@ SECTIONS
|
||||||
|
__ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) {
|
||||||
|
__start___ex_table = .;
|
||||||
|
#ifdef CONFIG_MMU
|
||||||
|
- *(__ex_table)
|
||||||
|
+ KEEP(*(__ex_table))
|
||||||
|
#endif
|
||||||
|
__stop___ex_table = .;
|
||||||
|
}
|
||||||
|
@@ -146,12 +146,12 @@ SECTIONS
|
||||||
|
. = 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 = .;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
@@ -171,14 +171,14 @@ SECTIONS
|
||||||
|
*/
|
||||||
|
__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 = .;
|
||||||
|
@@ -194,24 +194,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 = .;
|
||||||
|
}
|
||||||
|
.init.data : {
|
||||||
|
--- a/arch/arm/boot/compressed/Makefile
|
||||||
|
+++ b/arch/arm/boot/compressed/Makefile
|
||||||
|
@@ -102,6 +102,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/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -81,6 +81,7 @@ config ARM
|
||||||
|
select HAVE_UID16
|
||||||
|
select HAVE_VIRT_CPU_ACCOUNTING_GEN
|
||||||
|
select IRQ_FORCED_THREADING
|
||||||
|
+ select LD_DEAD_CODE_DATA_ELIMINATION
|
||||||
|
select MODULES_USE_ELF_REL
|
||||||
|
select NO_BOOTMEM
|
||||||
|
select OF_EARLY_FLATTREE if OF
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -55,6 +55,7 @@ config MIPS
|
||||||
|
select CLONE_BACKWARDS
|
||||||
|
select HAVE_DEBUG_STACKOVERFLOW
|
||||||
|
select HAVE_CC_STACKPROTECTOR
|
||||||
|
+ select LD_DEAD_CODE_DATA_ELIMINATION
|
||||||
|
select CPU_PM if CPU_IDLE
|
||||||
|
select ARCH_HAS_TICK_BROADCAST if GENERIC_CLOCKEVENTS_BROADCAST
|
||||||
|
select ARCH_BINFMT_ELF_STATE
|
||||||
|
--- a/Makefile
|
||||||
|
+++ b/Makefile
|
||||||
|
@@ -409,6 +409,11 @@ KBUILD_AFLAGS_MODULE := -DMODULE
|
||||||
|
KBUILD_CFLAGS_MODULE := -DMODULE
|
||||||
|
KBUILD_LDFLAGS_MODULE = -T $(srctree)/scripts/module-common.lds $(if $(CONFIG_PROFILING),,-s)
|
||||||
|
|
||||||
|
+ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
|
||||||
|
+KBUILD_CFLAGS_KERNEL += $(call cc-option,-ffunction-sections,)
|
||||||
|
+KBUILD_CFLAGS_KERNEL += $(call cc-option,-fdata-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)
|
||||||
|
@@ -630,11 +635,6 @@ include arch/$(SRCARCH)/Makefile
|
||||||
|
KBUILD_CFLAGS += $(call cc-option,-fno-delete-null-pointer-checks,)
|
||||||
|
KBUILD_CFLAGS += $(call cc-disable-warning,frame-address,)
|
||||||
|
|
||||||
|
-ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION
|
||||||
|
-KBUILD_CFLAGS += $(call cc-option,-ffunction-sections,)
|
||||||
|
-KBUILD_CFLAGS += $(call cc-option,-fdata-sections,)
|
||||||
|
-endif
|
||||||
|
-
|
||||||
|
ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
|
||||||
|
KBUILD_CFLAGS += -Os $(call cc-disable-warning,maybe-uninitialized,) $(EXTRA_OPTIMIZATION)
|
||||||
|
else
|
|
@ -0,0 +1,88 @@
|
||||||
|
--- 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
|
||||||
|
+
|
||||||
|
#include <linux/export.h>
|
||||||
|
|
||||||
|
/* Align . to a 8 byte boundary equals to maximum function alignment. */
|
||||||
|
@@ -329,14 +339,14 @@
|
||||||
|
/* Kernel symbol table: Normal symbols */ \
|
||||||
|
__ksymtab : AT(ADDR(__ksymtab) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___ksymtab) = .; \
|
||||||
|
- KEEP(*(SORT(___ksymtab+*))) \
|
||||||
|
+ SYMTAB_KEEP \
|
||||||
|
VMLINUX_SYMBOL(__stop___ksymtab) = .; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* Kernel symbol table: GPL-only symbols */ \
|
||||||
|
__ksymtab_gpl : AT(ADDR(__ksymtab_gpl) - LOAD_OFFSET) { \
|
||||||
|
VMLINUX_SYMBOL(__start___ksymtab_gpl) = .; \
|
||||||
|
- KEEP(*(SORT(___ksymtab_gpl+*))) \
|
||||||
|
+ SYMTAB_KEEP_GPL \
|
||||||
|
VMLINUX_SYMBOL(__stop___ksymtab_gpl) = .; \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
@@ -398,7 +408,7 @@
|
||||||
|
\
|
||||||
|
/* Kernel symbol table: strings */ \
|
||||||
|
__ksymtab_strings : AT(ADDR(__ksymtab_strings) - LOAD_OFFSET) { \
|
||||||
|
- *(__ksymtab_strings) \
|
||||||
|
+ *(__ksymtab_strings+*) \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
/* __*init sections */ \
|
||||||
|
@@ -749,6 +759,8 @@
|
||||||
|
EXIT_TEXT \
|
||||||
|
EXIT_DATA \
|
||||||
|
EXIT_CALL \
|
||||||
|
+ SYMTAB_DISCARD \
|
||||||
|
+ SYMTAB_DISCARD_GPL \
|
||||||
|
*(.discard) \
|
||||||
|
*(.discard.*) \
|
||||||
|
}
|
||||||
|
--- a/scripts/Makefile.build
|
||||||
|
+++ b/scripts/Makefile.build
|
||||||
|
@@ -398,7 +398,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 -C -U$(ARCH) \
|
||||||
|
+ cmd_cpp_lds_S = $(CPP) $(EXTRA_LDSFLAGS) $(cpp_flags) -P -C -U$(ARCH) \
|
||||||
|
-D__ASSEMBLY__ -DLINKER_SCRIPT -o $@ $<
|
||||||
|
|
||||||
|
$(obj)/%.lds: $(src)/%.lds.S FORCE
|
||||||
|
--- a/include/linux/export.h
|
||||||
|
+++ b/include/linux/export.h
|
||||||
|
@@ -53,12 +53,19 @@ extern struct module __this_module;
|
||||||
|
#define __CRC_SYMBOL(sym, sec)
|
||||||
|
#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"), aligned(1))) \
|
||||||
|
+ __attribute__((section("__ksymtab_strings" \
|
||||||
|
+ __EXPORT_SUFFIX(sym)), aligned(1))) \
|
||||||
|
= VMLINUX_SYMBOL_STR(sym); \
|
||||||
|
static const struct kernel_symbol __ksymtab_##sym \
|
||||||
|
__used \
|
|
@ -0,0 +1,124 @@
|
||||||
|
ARM: implement "uncompressed zImage"
|
||||||
|
|
||||||
|
Based on RFC patch by Uwe Kleine-König
|
||||||
|
http://www.spinics.net/lists/arm-kernel/msg230153.html
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
--- a/arch/arm/boot/compressed/Makefile
|
||||||
|
+++ b/arch/arm/boot/compressed/Makefile
|
||||||
|
@@ -71,6 +71,7 @@ compress-$(CONFIG_KERNEL_LZO) = lzo
|
||||||
|
compress-$(CONFIG_KERNEL_LZMA) = lzma
|
||||||
|
compress-$(CONFIG_KERNEL_XZ) = xzkern
|
||||||
|
compress-$(CONFIG_KERNEL_LZ4) = lz4
|
||||||
|
+compress-$(CONFIG_KERNEL_CAT) = cat
|
||||||
|
|
||||||
|
# Borrowed libfdt files for the ATAG compatibility mode
|
||||||
|
|
||||||
|
--- a/arch/arm/boot/compressed/decompress.c
|
||||||
|
+++ b/arch/arm/boot/compressed/decompress.c
|
||||||
|
@@ -55,6 +55,10 @@ extern char * strstr(const char * s1, co
|
||||||
|
#include "../../../../lib/decompress_unlz4.c"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+#ifdef CONFIG_KERNEL_CAT
|
||||||
|
+#include "../../../../lib/decompress_uncat.c"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
int do_decompress(u8 *input, int len, u8 *output, void (*error)(char *x))
|
||||||
|
{
|
||||||
|
return __decompress(input, len, NULL, NULL, output, 0, NULL, error);
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/arm/boot/compressed/piggy.cat.S
|
||||||
|
@@ -0,0 +1,6 @@
|
||||||
|
+ .section .piggydata,#alloc
|
||||||
|
+ .globl input_data
|
||||||
|
+input_data:
|
||||||
|
+ .incbin "arch/arm/boot/compressed/piggy.cat"
|
||||||
|
+ .globl input_data_end
|
||||||
|
+input_data_end:
|
||||||
|
--- a/init/Kconfig
|
||||||
|
+++ b/init/Kconfig
|
||||||
|
@@ -127,6 +127,9 @@ config HAVE_KERNEL_LZO
|
||||||
|
config HAVE_KERNEL_LZ4
|
||||||
|
bool
|
||||||
|
|
||||||
|
+config HAVE_KERNEL_CAT
|
||||||
|
+ bool
|
||||||
|
+
|
||||||
|
choice
|
||||||
|
prompt "Kernel compression mode"
|
||||||
|
default KERNEL_GZIP
|
||||||
|
@@ -193,9 +196,10 @@ config KERNEL_LZO
|
||||||
|
bool "LZO"
|
||||||
|
depends on HAVE_KERNEL_LZO
|
||||||
|
help
|
||||||
|
- Its compression ratio is the poorest among the choices. The kernel
|
||||||
|
- size is about 10% bigger than gzip; however its speed
|
||||||
|
- (both compression and decompression) is the fastest.
|
||||||
|
+ Its compression ratio is the poorest among the choices (apart from
|
||||||
|
+ uncompressed below). The kernel size is about 10% bigger than gzip;
|
||||||
|
+ however its speed (both compression and decompression) is the
|
||||||
|
+ fastest.
|
||||||
|
|
||||||
|
config KERNEL_LZ4
|
||||||
|
bool "LZ4"
|
||||||
|
@@ -209,6 +213,12 @@ config KERNEL_LZ4
|
||||||
|
is about 8% bigger than LZO. But the decompression speed is
|
||||||
|
faster than LZO.
|
||||||
|
|
||||||
|
+config KERNEL_CAT
|
||||||
|
+ bool "uncompressed"
|
||||||
|
+ depends on HAVE_KERNEL_CAT
|
||||||
|
+ help
|
||||||
|
+ Don't use compression at all.
|
||||||
|
+
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
config DEFAULT_HOSTNAME
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/lib/decompress_uncat.c
|
||||||
|
@@ -0,0 +1,17 @@
|
||||||
|
+#include <linux/types.h>
|
||||||
|
+#include <linux/compiler.h>
|
||||||
|
+
|
||||||
|
+#ifdef STATIC
|
||||||
|
+
|
||||||
|
+STATIC int __decompress(unsigned char *buf, long in_len,
|
||||||
|
+ long (*fill)(void*, unsigned long),
|
||||||
|
+ long (*flush)(void*, unsigned long),
|
||||||
|
+ unsigned char *output, long out_len,
|
||||||
|
+ long *posp,
|
||||||
|
+ void (*error)(char *x))
|
||||||
|
+{
|
||||||
|
+ memmove(output, buf, in_len);
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
--- a/scripts/Makefile.lib
|
||||||
|
+++ b/scripts/Makefile.lib
|
||||||
|
@@ -357,6 +357,13 @@ cmd_lz4 = (cat $(filter-out FORCE,$^) |
|
||||||
|
lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||||
|
(rm -f $@ ; false)
|
||||||
|
|
||||||
|
+# uncompressed
|
||||||
|
+# ---------------------------------------------------------------------------
|
||||||
|
+quiet_cmd_cat = CAT $@
|
||||||
|
+cmd_cat = (cat $(filter-out FORCE,$^) \
|
||||||
|
+ && $(call size_append, $(filter-out FORCE,$^))) > $@ || \
|
||||||
|
+ (rm -f $@ ; false)
|
||||||
|
+
|
||||||
|
# U-Boot mkimage
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
--- a/arch/arm/Kconfig
|
||||||
|
+++ b/arch/arm/Kconfig
|
||||||
|
@@ -65,6 +65,7 @@ config ARM
|
||||||
|
select HAVE_KERNEL_LZMA
|
||||||
|
select HAVE_KERNEL_LZO
|
||||||
|
select HAVE_KERNEL_XZ
|
||||||
|
+ select HAVE_KERNEL_CAT
|
||||||
|
select HAVE_KPROBES if !XIP_KERNEL && !CPU_ENDIAN_BE32 && !CPU_V7M
|
||||||
|
select HAVE_KRETPROBES if (HAVE_KPROBES)
|
||||||
|
select HAVE_MEMBLOCK
|
|
@ -0,0 +1,58 @@
|
||||||
|
--- a/scripts/Makefile.lib
|
||||||
|
+++ b/scripts/Makefile.lib
|
||||||
|
@@ -344,7 +344,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/scripts/gen_initramfs_list.sh
|
||||||
|
+++ b/scripts/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"
|
||||||
|
@@ -318,7 +318,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}
|
||||||
|
--- a/lib/decompress.c
|
||||||
|
+++ b/lib/decompress.c
|
||||||
|
@@ -48,6 +48,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 },
|
|
@ -0,0 +1,29 @@
|
||||||
|
--- a/usr/Makefile
|
||||||
|
+++ b/usr/Makefile
|
||||||
|
@@ -53,6 +53,8 @@ ifneq ($(wildcard $(obj)/.initramfs_data
|
||||||
|
include $(obj)/.initramfs_data.cpio.d
|
||||||
|
endif
|
||||||
|
|
||||||
|
+deps_initramfs_sane := $(foreach v,$(deps_initramfs),$(if $(findstring :,$(v)),,$(v)))
|
||||||
|
+
|
||||||
|
quiet_cmd_initfs = GEN $@
|
||||||
|
cmd_initfs = $(initramfs) -o $@ $(ramfs-args) $(ramfs-input)
|
||||||
|
|
||||||
|
@@ -61,14 +63,14 @@ targets := initramfs_data.cpio.gz initra
|
||||||
|
initramfs_data.cpio.lzo initramfs_data.cpio.lz4 \
|
||||||
|
initramfs_data.cpio
|
||||||
|
# do not try to update files included in initramfs
|
||||||
|
-$(deps_initramfs): ;
|
||||||
|
+$(deps_initramfs_sane): ;
|
||||||
|
|
||||||
|
-$(deps_initramfs): klibcdirs
|
||||||
|
+$(deps_initramfs_sane): klibcdirs
|
||||||
|
# We rebuild initramfs_data.cpio if:
|
||||||
|
# 1) Any included file is newer then initramfs_data.cpio
|
||||||
|
# 2) There are changes in which files are included (added or deleted)
|
||||||
|
# 3) If gen_init_cpio are newer than initramfs_data.cpio
|
||||||
|
# 4) arguments to gen_initramfs.sh changes
|
||||||
|
-$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs) klibcdirs
|
||||||
|
+$(obj)/initramfs_data.cpio$(suffix_y): $(obj)/gen_init_cpio $(deps_initramfs_sane) klibcdirs
|
||||||
|
$(Q)$(initramfs) -l $(ramfs-input) > $(obj)/.initramfs_data.cpio.d
|
||||||
|
$(call if_changed,initfs)
|
|
@ -0,0 +1,18 @@
|
||||||
|
--- a/net/netfilter/Kconfig
|
||||||
|
+++ b/net/netfilter/Kconfig
|
||||||
|
@@ -218,7 +218,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
|
||||||
|
@@ -968,7 +967,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
|
|
@ -0,0 +1,18 @@
|
||||||
|
--- a/sound/core/Kconfig
|
||||||
|
+++ b/sound/core/Kconfig
|
||||||
|
@@ -16,13 +16,13 @@ config SND_DMAENGINE_PCM
|
||||||
|
tristate
|
||||||
|
|
||||||
|
config SND_HWDEP
|
||||||
|
- tristate
|
||||||
|
+ tristate "Sound hardware support"
|
||||||
|
|
||||||
|
config SND_RAWMIDI
|
||||||
|
tristate
|
||||||
|
|
||||||
|
config SND_COMPRESS_OFFLOAD
|
||||||
|
- tristate
|
||||||
|
+ tristate "Compression offloading support"
|
||||||
|
|
||||||
|
config SND_JACK
|
||||||
|
bool
|
|
@ -0,0 +1,10 @@
|
||||||
|
--- a/drivers/crypto/Kconfig
|
||||||
|
+++ b/drivers/crypto/Kconfig
|
||||||
|
@@ -176,6 +176,7 @@ config CRYPTO_DEV_MV_CESA
|
||||||
|
tristate "Marvell's Cryptographic Engine"
|
||||||
|
depends on PLAT_ORION
|
||||||
|
select CRYPTO_AES
|
||||||
|
+ select CRYPTO_HASH2
|
||||||
|
select CRYPTO_BLKCIPHER
|
||||||
|
select CRYPTO_HASH
|
||||||
|
select SRAM
|
|
@ -0,0 +1,29 @@
|
||||||
|
--- a/drivers/ssb/Kconfig
|
||||||
|
+++ b/drivers/ssb/Kconfig
|
||||||
|
@@ -29,6 +29,7 @@ config SSB_SPROM
|
||||||
|
config SSB_BLOCKIO
|
||||||
|
bool
|
||||||
|
depends on SSB
|
||||||
|
+ default y
|
||||||
|
|
||||||
|
config SSB_PCIHOST_POSSIBLE
|
||||||
|
bool
|
||||||
|
@@ -49,7 +50,7 @@ config SSB_PCIHOST
|
||||||
|
config SSB_B43_PCI_BRIDGE
|
||||||
|
bool
|
||||||
|
depends on SSB_PCIHOST
|
||||||
|
- default n
|
||||||
|
+ default y
|
||||||
|
|
||||||
|
config SSB_PCMCIAHOST_POSSIBLE
|
||||||
|
bool
|
||||||
|
--- a/drivers/bcma/Kconfig
|
||||||
|
+++ b/drivers/bcma/Kconfig
|
||||||
|
@@ -17,6 +17,7 @@ config BCMA
|
||||||
|
config BCMA_BLOCKIO
|
||||||
|
bool
|
||||||
|
depends on BCMA
|
||||||
|
+ default y
|
||||||
|
|
||||||
|
config BCMA_HOST_PCI_POSSIBLE
|
||||||
|
bool
|
|
@ -0,0 +1,23 @@
|
||||||
|
--- a/lib/Kconfig
|
||||||
|
+++ b/lib/Kconfig
|
||||||
|
@@ -334,16 +334,16 @@ config BCH_CONST_T
|
||||||
|
# Textsearch support is select'ed if needed
|
||||||
|
#
|
||||||
|
config TEXTSEARCH
|
||||||
|
- bool
|
||||||
|
+ boolean "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
|
|
@ -0,0 +1,31 @@
|
||||||
|
--- a/net/wireless/Kconfig
|
||||||
|
+++ b/net/wireless/Kconfig
|
||||||
|
@@ -188,7 +188,7 @@ config CFG80211_WEXT_EXPORT
|
||||||
|
wext compatibility symbols to be exported.
|
||||||
|
|
||||||
|
config LIB80211
|
||||||
|
- tristate
|
||||||
|
+ tristate "LIB80211"
|
||||||
|
default n
|
||||||
|
help
|
||||||
|
This options enables a library of common routines used
|
||||||
|
@@ -197,13 +197,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"
|
|
@ -0,0 +1,47 @@
|
||||||
|
--- a/crypto/Kconfig
|
||||||
|
+++ b/crypto/Kconfig
|
||||||
|
@@ -32,7 +32,7 @@ config CRYPTO_FIPS
|
||||||
|
this is.
|
||||||
|
|
||||||
|
config CRYPTO_ALGAPI
|
||||||
|
- tristate
|
||||||
|
+ tristate "ALGAPI"
|
||||||
|
select CRYPTO_ALGAPI2
|
||||||
|
help
|
||||||
|
This option provides the API for cryptographic algorithms.
|
||||||
|
@@ -41,7 +41,7 @@ config CRYPTO_ALGAPI2
|
||||||
|
tristate
|
||||||
|
|
||||||
|
config CRYPTO_AEAD
|
||||||
|
- tristate
|
||||||
|
+ tristate "AEAD"
|
||||||
|
select CRYPTO_AEAD2
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
|
||||||
|
@@ -52,7 +52,7 @@ config CRYPTO_AEAD2
|
||||||
|
select CRYPTO_RNG2
|
||||||
|
|
||||||
|
config CRYPTO_BLKCIPHER
|
||||||
|
- tristate
|
||||||
|
+ tristate "BLKCIPHER"
|
||||||
|
select CRYPTO_BLKCIPHER2
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
|
||||||
|
@@ -63,7 +63,7 @@ config CRYPTO_BLKCIPHER2
|
||||||
|
select CRYPTO_WORKQUEUE
|
||||||
|
|
||||||
|
config CRYPTO_HASH
|
||||||
|
- tristate
|
||||||
|
+ tristate "HASH"
|
||||||
|
select CRYPTO_HASH2
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ config CRYPTO_HASH2
|
||||||
|
select CRYPTO_ALGAPI2
|
||||||
|
|
||||||
|
config CRYPTO_RNG
|
||||||
|
- tristate
|
||||||
|
+ tristate "RNG"
|
||||||
|
select CRYPTO_RNG2
|
||||||
|
select CRYPTO_ALGAPI
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
--- 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"
|
|
@ -0,0 +1,11 @@
|
||||||
|
--- 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_NETLINK_ACCT
|
||||||
|
tristate "Netfilter NFACCT over NFNETLINK interface"
|
|
@ -0,0 +1,87 @@
|
||||||
|
--- a/drivers/base/regmap/Kconfig
|
||||||
|
+++ b/drivers/base/regmap/Kconfig
|
||||||
|
@@ -3,29 +3,35 @@
|
||||||
|
# subsystems should select the appropriate symbols.
|
||||||
|
|
||||||
|
config REGMAP
|
||||||
|
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
|
||||||
|
select LZO_COMPRESS
|
||||||
|
select LZO_DECOMPRESS
|
||||||
|
select IRQ_DOMAIN if REGMAP_IRQ
|
||||||
|
- bool
|
||||||
|
+ tristate "Regmap"
|
||||||
|
|
||||||
|
config REGMAP_AC97
|
||||||
|
+ select REGMAP
|
||||||
|
tristate
|
||||||
|
|
||||||
|
config REGMAP_I2C
|
||||||
|
- tristate
|
||||||
|
+ tristate "Regmap I2C"
|
||||||
|
+ select REGMAP
|
||||||
|
depends on I2C
|
||||||
|
|
||||||
|
config REGMAP_SPI
|
||||||
|
- tristate
|
||||||
|
+ tristate "Regmap SPI"
|
||||||
|
+ select REGMAP
|
||||||
|
+ depends on SPI_MASTER
|
||||||
|
depends on SPI
|
||||||
|
|
||||||
|
config REGMAP_SPMI
|
||||||
|
+ select REGMAP
|
||||||
|
tristate
|
||||||
|
depends on SPMI
|
||||||
|
|
||||||
|
config REGMAP_MMIO
|
||||||
|
- tristate
|
||||||
|
+ tristate "Regmap MMIO"
|
||||||
|
+ select REGMAP
|
||||||
|
|
||||||
|
config REGMAP_IRQ
|
||||||
|
+ select REGMAP
|
||||||
|
bool
|
||||||
|
--- a/include/linux/regmap.h
|
||||||
|
+++ b/include/linux/regmap.h
|
||||||
|
@@ -135,7 +135,7 @@ struct reg_sequence {
|
||||||
|
pollret ?: ((cond) ? 0 : -ETIMEDOUT); \
|
||||||
|
})
|
||||||
|
|
||||||
|
-#ifdef CONFIG_REGMAP
|
||||||
|
+#if IS_ENABLED(CONFIG_REGMAP)
|
||||||
|
|
||||||
|
enum regmap_endian {
|
||||||
|
/* Unspecified -> 0 -> Backwards compatible default */
|
||||||
|
--- a/drivers/base/regmap/Makefile
|
||||||
|
+++ b/drivers/base/regmap/Makefile
|
||||||
|
@@ -1,9 +1,11 @@
|
||||||
|
# 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-lzo.o regcache-flat.o
|
||||||
|
-obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
|
||||||
|
+regmap-core-objs = regmap.o regcache.o regcache-rbtree.o regcache-lzo.o regcache-flat.o
|
||||||
|
+ifdef CONFIG_DEBUG_FS
|
||||||
|
+regmap-core-objs += regmap-debugfs.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_SPI) += regmap-spi.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>
|
||||||
|
@@ -2913,3 +2914,5 @@ static int __init regmap_initcall(void)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
postcore_initcall(regmap_initcall);
|
||||||
|
+
|
||||||
|
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,48 @@
|
||||||
|
--- a/crypto/Kconfig
|
||||||
|
+++ b/crypto/Kconfig
|
||||||
|
@@ -132,12 +132,12 @@ 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
|
||||||
|
+ 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
|
||||||
|
|
||||||
|
config CRYPTO_USER
|
||||||
|
tristate "Userspace cryptographic algorithm configuration"
|
||||||
|
@@ -150,7 +150,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
|
||||||
|
@@ -248,12 +248,16 @@ static int cryptomgr_schedule_test(struc
|
||||||
|
type = alg->cra_flags;
|
||||||
|
|
||||||
|
/* This piece of crap needs to disappear into per-type test hooks. */
|
||||||
|
+#ifdef CONFIG_CRYPTO_MANAGER_DISABLE_TESTS
|
||||||
|
+ type |= CRYPTO_ALG_TESTED;
|
||||||
|
+#else
|
||||||
|
if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) &
|
||||||
|
CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV) &&
|
||||||
|
((alg->cra_flags & CRYPTO_ALG_TYPE_MASK) ==
|
||||||
|
CRYPTO_ALG_TYPE_BLKCIPHER ? alg->cra_blkcipher.ivsize :
|
||||||
|
alg->cra_ablkcipher.ivsize))
|
||||||
|
type |= CRYPTO_ALG_TESTED;
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
param->type = type;
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
We use backports for driver updates - make sure we can compile in the glue code regardless
|
||||||
|
|
||||||
|
Signed-off-by: Imre Kaloz <kaloz@openwrt.org>
|
||||||
|
|
||||||
|
--- a/drivers/net/wireless/ti/Kconfig
|
||||||
|
+++ b/drivers/net/wireless/ti/Kconfig
|
||||||
|
@@ -19,7 +19,7 @@ source "drivers/net/wireless/ti/wlcore/K
|
||||||
|
|
||||||
|
config WILINK_PLATFORM_DATA
|
||||||
|
bool "TI WiLink platform data"
|
||||||
|
- depends on WLCORE_SDIO || WL1251_SDIO
|
||||||
|
+ depends on WLCORE_SDIO || WL1251_SDIO || ARCH_OMAP2PLUS
|
||||||
|
default y
|
||||||
|
---help---
|
||||||
|
Small platform data bit needed to pass data to the sdio modules.
|
|
@ -0,0 +1,34 @@
|
||||||
|
From 8b05e325824d3b38e52a7748b3b5dc34dc1c0f6d Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Date: Mon, 29 Jun 2015 14:37:54 +0200
|
||||||
|
Subject: [PATCH 1/3] uapi/kernel.h: glibc specific inclusion of sysinfo.h
|
||||||
|
|
||||||
|
including sysinfo.h from kernel.h makes no sense whatsoever,
|
||||||
|
but removing it breaks glibc's userspace header,
|
||||||
|
which includes kernel.h instead of sysinfo.h from their sys/sysinfo.h.
|
||||||
|
this seems to be a historical mistake.
|
||||||
|
on musl, including any header that uses kernel.h directly or indirectly
|
||||||
|
plus sys/sysinfo.h will produce a compile error due to redefinition of
|
||||||
|
struct sysinfo from sys/sysinfo.h.
|
||||||
|
so for now, only include it on glibc or when including from kernel
|
||||||
|
in order not to break their headers.
|
||||||
|
|
||||||
|
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||||
|
Signed-off-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||||
|
---
|
||||||
|
include/uapi/linux/kernel.h | 2 ++
|
||||||
|
1 file changed, 2 insertions(+)
|
||||||
|
|
||||||
|
--- a/include/uapi/linux/kernel.h
|
||||||
|
+++ b/include/uapi/linux/kernel.h
|
||||||
|
@@ -1,7 +1,9 @@
|
||||||
|
#ifndef _UAPI_LINUX_KERNEL_H
|
||||||
|
#define _UAPI_LINUX_KERNEL_H
|
||||||
|
|
||||||
|
+#if defined(__KERNEL__) || defined( __GLIBC__)
|
||||||
|
#include <linux/sysinfo.h>
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 'kernel.h' contains some often-used function prototypes etc
|
|
@ -0,0 +1,107 @@
|
||||||
|
From f972afc2509eebcb00d370256c55b112a3b5ffca Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Date: Mon, 29 Jun 2015 16:50:40 +0200
|
||||||
|
Subject: [PATCH 2/3] uapi/libc-compat.h: do not rely on __GLIBC__
|
||||||
|
|
||||||
|
Musl provides the same structs as glibc, but does not provide a define to
|
||||||
|
allow its detection. Since the absence of __GLIBC__ also can mean that it
|
||||||
|
is included from the kernel, change the __GLIBC__ detection to
|
||||||
|
!__KERNEL__, which should always be true when included from userspace.
|
||||||
|
|
||||||
|
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||||
|
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||||
|
---
|
||||||
|
include/uapi/linux/libc-compat.h | 18 +++++++++---------
|
||||||
|
1 file changed, 9 insertions(+), 9 deletions(-)
|
||||||
|
|
||||||
|
--- a/include/uapi/linux/libc-compat.h
|
||||||
|
+++ b/include/uapi/linux/libc-compat.h
|
||||||
|
@@ -48,13 +48,13 @@
|
||||||
|
#ifndef _UAPI_LIBC_COMPAT_H
|
||||||
|
#define _UAPI_LIBC_COMPAT_H
|
||||||
|
|
||||||
|
-/* We have included glibc headers... */
|
||||||
|
-#if defined(__GLIBC__)
|
||||||
|
+/* We have included libc headers... */
|
||||||
|
+#if !defined(__KERNEL__)
|
||||||
|
|
||||||
|
-/* Coordinate with glibc net/if.h header. */
|
||||||
|
-#if defined(_NET_IF_H) && defined(__USE_MISC)
|
||||||
|
+/* Coordinate with libc net/if.h header. */
|
||||||
|
+#if defined(_NET_IF_H) && (!defined(__GLIBC__) || defined(__USE_MISC))
|
||||||
|
|
||||||
|
-/* GLIBC headers included first so don't define anything
|
||||||
|
+/* LIBC headers included first so don't define anything
|
||||||
|
* that would already be defined. */
|
||||||
|
|
||||||
|
#define __UAPI_DEF_IF_IFCONF 0
|
||||||
|
@@ -65,7 +65,11 @@
|
||||||
|
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS 0
|
||||||
|
/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
|
||||||
|
#ifndef __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO
|
||||||
|
+#ifdef __GLIBC__
|
||||||
|
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
|
||||||
|
+#else
|
||||||
|
+#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 0
|
||||||
|
+#endif
|
||||||
|
#endif /* __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO */
|
||||||
|
|
||||||
|
#else /* _NET_IF_H */
|
||||||
|
@@ -85,10 +89,10 @@
|
||||||
|
|
||||||
|
#endif /* _NET_IF_H */
|
||||||
|
|
||||||
|
-/* Coordinate with glibc netinet/in.h header. */
|
||||||
|
+/* Coordinate with libc netinet/in.h header. */
|
||||||
|
#if defined(_NETINET_IN_H)
|
||||||
|
|
||||||
|
-/* GLIBC headers included first so don't define anything
|
||||||
|
+/* LIBC headers included first so don't define anything
|
||||||
|
* that would already be defined. */
|
||||||
|
#define __UAPI_DEF_IN_ADDR 0
|
||||||
|
#define __UAPI_DEF_IN_IPPROTO 0
|
||||||
|
@@ -102,7 +106,7 @@
|
||||||
|
* if the glibc code didn't define them. This guard matches
|
||||||
|
* the guard in glibc/inet/netinet/in.h which defines the
|
||||||
|
* additional in6_addr macros e.g. s6_addr16, and s6_addr32. */
|
||||||
|
-#if defined(__USE_MISC) || defined (__USE_GNU)
|
||||||
|
+#if !defined(__GLIBC__) || defined(__USE_MISC) || defined (__USE_GNU)
|
||||||
|
#define __UAPI_DEF_IN6_ADDR_ALT 0
|
||||||
|
#else
|
||||||
|
#define __UAPI_DEF_IN6_ADDR_ALT 1
|
||||||
|
@@ -117,7 +121,7 @@
|
||||||
|
#else
|
||||||
|
|
||||||
|
/* Linux headers included first, and we must define everything
|
||||||
|
- * we need. The expectation is that glibc will check the
|
||||||
|
+ * we need. The expectation is that the libc will check the
|
||||||
|
* __UAPI_DEF_* defines and adjust appropriately. */
|
||||||
|
#define __UAPI_DEF_IN_ADDR 1
|
||||||
|
#define __UAPI_DEF_IN_IPPROTO 1
|
||||||
|
@@ -127,7 +131,7 @@
|
||||||
|
#define __UAPI_DEF_IN_CLASS 1
|
||||||
|
|
||||||
|
#define __UAPI_DEF_IN6_ADDR 1
|
||||||
|
-/* We unconditionally define the in6_addr macros and glibc must
|
||||||
|
+/* We unconditionally define the in6_addr macros and the libc must
|
||||||
|
* coordinate. */
|
||||||
|
#define __UAPI_DEF_IN6_ADDR_ALT 1
|
||||||
|
#define __UAPI_DEF_SOCKADDR_IN6 1
|
||||||
|
@@ -168,7 +172,7 @@
|
||||||
|
/* If we did not see any headers from any supported C libraries,
|
||||||
|
* or we are being included in the kernel, then define everything
|
||||||
|
* that we need. */
|
||||||
|
-#else /* !defined(__GLIBC__) */
|
||||||
|
+#else /* defined(__KERNEL__) */
|
||||||
|
|
||||||
|
/* Definitions for if.h */
|
||||||
|
#define __UAPI_DEF_IF_IFCONF 1
|
||||||
|
@@ -208,6 +212,6 @@
|
||||||
|
/* Definitions for xattr.h */
|
||||||
|
#define __UAPI_DEF_XATTR 1
|
||||||
|
|
||||||
|
-#endif /* __GLIBC__ */
|
||||||
|
+#endif /* __KERNEL__ */
|
||||||
|
|
||||||
|
#endif /* _UAPI_LIBC_COMPAT_H */
|
|
@ -0,0 +1,67 @@
|
||||||
|
From fcbb6fed85ea9ff4feb4f1ebd4f0f235fdaf06b6 Mon Sep 17 00:00:00 2001
|
||||||
|
From: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Date: Mon, 29 Jun 2015 16:53:03 +0200
|
||||||
|
Subject: [PATCH 3/3] uapi/if_ether.h: prevent redefinition of struct ethhdr
|
||||||
|
|
||||||
|
Musl provides its own ethhdr struct definition. Add a guard to prevent
|
||||||
|
its definition of the appropriate musl header has already been included.
|
||||||
|
|
||||||
|
Signed-off-by: John Spencer <maillist-linux@barfooze.de>
|
||||||
|
Tested-by: David Heidelberger <david.heidelberger@ixit.cz>
|
||||||
|
Signed-off-by: Jonas Gorski <jogo@openwrt.org>
|
||||||
|
---
|
||||||
|
include/uapi/linux/if_ether.h | 3 +++
|
||||||
|
include/uapi/linux/libc-compat.h | 11 +++++++++++
|
||||||
|
2 files changed, 14 insertions(+)
|
||||||
|
|
||||||
|
--- a/include/uapi/linux/if_ether.h
|
||||||
|
+++ b/include/uapi/linux/if_ether.h
|
||||||
|
@@ -22,6 +22,7 @@
|
||||||
|
#define _UAPI_LINUX_IF_ETHER_H
|
||||||
|
|
||||||
|
#include <linux/types.h>
|
||||||
|
+#include <linux/libc-compat.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IEEE 802.3 Ethernet magic constants. The frame sizes omit the preamble
|
||||||
|
@@ -138,11 +139,13 @@
|
||||||
|
* This is an Ethernet frame header.
|
||||||
|
*/
|
||||||
|
|
||||||
|
+#if __UAPI_DEF_ETHHDR
|
||||||
|
struct ethhdr {
|
||||||
|
unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
|
||||||
|
unsigned char h_source[ETH_ALEN]; /* source ether addr */
|
||||||
|
__be16 h_proto; /* packet type ID field */
|
||||||
|
} __attribute__((packed));
|
||||||
|
+#endif
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* _UAPI_LINUX_IF_ETHER_H */
|
||||||
|
--- a/include/uapi/linux/libc-compat.h
|
||||||
|
+++ b/include/uapi/linux/libc-compat.h
|
||||||
|
@@ -89,6 +89,14 @@
|
||||||
|
|
||||||
|
#endif /* _NET_IF_H */
|
||||||
|
|
||||||
|
+/* musl defines the ethhdr struct itself in its netinet/if_ether.h.
|
||||||
|
+ * Glibc just includes the kernel header and uses a different guard. */
|
||||||
|
+#if defined(_NETINET_IF_ETHER_H)
|
||||||
|
+#define __UAPI_DEF_ETHHDR 0
|
||||||
|
+#else
|
||||||
|
+#define __UAPI_DEF_ETHHDR 1
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
/* Coordinate with libc netinet/in.h header. */
|
||||||
|
#if defined(_NETINET_IN_H)
|
||||||
|
|
||||||
|
@@ -184,6 +192,9 @@
|
||||||
|
/* For the future if glibc adds IFF_LOWER_UP, IFF_DORMANT and IFF_ECHO */
|
||||||
|
#define __UAPI_DEF_IF_NET_DEVICE_FLAGS_LOWER_UP_DORMANT_ECHO 1
|
||||||
|
|
||||||
|
+/* Definitions for if_ether.h */
|
||||||
|
+#define __UAPI_DEF_ETHHDR 1
|
||||||
|
+
|
||||||
|
/* Definitions for in.h */
|
||||||
|
#define __UAPI_DEF_IN_ADDR 1
|
||||||
|
#define __UAPI_DEF_IN_IPPROTO 1
|
|
@ -0,0 +1,79 @@
|
||||||
|
--- 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_REGULATOR
|
||||||
|
tristate "Generic rfkill regulator driver"
|
||||||
|
- depends on RFKILL || !RFKILL
|
||||||
|
+ depends on RFKILL_FULL || !RFKILL_FULL
|
||||||
|
depends on REGULATOR
|
||||||
|
help
|
||||||
|
This options enable controlling radio transmitters connected to
|
||||||
|
@@ -36,7 +40,7 @@ config RFKILL_REGULATOR
|
||||||
|
|
||||||
|
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,6 +4,6 @@
|
||||||
|
|
||||||
|
rfkill-y += core.o
|
||||||
|
rfkill-$(CONFIG_RFKILL_INPUT) += input.o
|
||||||
|
-obj-$(CONFIG_RFKILL) += rfkill.o
|
||||||
|
+obj-$(CONFIG_RFKILL_FULL) += rfkill.o
|
||||||
|
obj-$(CONFIG_RFKILL_REGULATOR) += rfkill-regulator.o
|
||||||
|
obj-$(CONFIG_RFKILL_GPIO) += rfkill-gpio.o
|
||||||
|
--- a/net/Makefile
|
||||||
|
+++ b/net/Makefile
|
||||||
|
@@ -51,7 +51,7 @@ obj-$(CONFIG_MAC80211) += mac80211/
|
||||||
|
obj-$(CONFIG_TIPC) += tipc/
|
||||||
|
obj-$(CONFIG_NETLABEL) += netlabel/
|
||||||
|
obj-$(CONFIG_IUCV) += iucv/
|
||||||
|
-obj-$(CONFIG_RFKILL) += rfkill/
|
||||||
|
+obj-$(CONFIG_RFKILL_FULL) += rfkill/
|
||||||
|
obj-$(CONFIG_NET_9P) += 9p/
|
||||||
|
obj-$(CONFIG_CAIF) += caif/
|
||||||
|
ifneq ($(CONFIG_DCB),)
|
||||||
|
--- 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
|
|
@ -0,0 +1,39 @@
|
||||||
|
From: Mark Miller <mark@mirell.org>
|
||||||
|
|
||||||
|
This exposes the CONFIG_BOOT_RAW symbol in Kconfig. This is needed on
|
||||||
|
certain Broadcom chipsets running CFE in order to load the kernel.
|
||||||
|
|
||||||
|
Signed-off-by: Mark Miller <mark@mirell.org>
|
||||||
|
Acked-by: Rob Landley <rob@landley.net>
|
||||||
|
---
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -1065,9 +1065,6 @@ config FW_ARC
|
||||||
|
config ARCH_MAY_HAVE_PC_FDC
|
||||||
|
bool
|
||||||
|
|
||||||
|
-config BOOT_RAW
|
||||||
|
- bool
|
||||||
|
-
|
||||||
|
config CEVT_BCM1480
|
||||||
|
bool
|
||||||
|
|
||||||
|
@@ -2963,6 +2960,18 @@ choice
|
||||||
|
bool "Extend builtin kernel arguments with bootloader arguments"
|
||||||
|
endchoice
|
||||||
|
|
||||||
|
+config BOOT_RAW
|
||||||
|
+ bool "Enable the kernel to be executed from the load address"
|
||||||
|
+ default n
|
||||||
|
+ help
|
||||||
|
+ Allow the kernel to be executed from the load address for
|
||||||
|
+ bootloaders which cannot read the ELF format. This places
|
||||||
|
+ a jump to start_kernel at the load address.
|
||||||
|
+
|
||||||
|
+ If unsure, say N.
|
||||||
|
+
|
||||||
|
+
|
||||||
|
+
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
config LOCKDEP_SUPPORT
|
|
@ -0,0 +1,28 @@
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -1150,6 +1150,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,11 @@
|
||||||
|
--- a/arch/mips/Makefile
|
||||||
|
+++ b/arch/mips/Makefile
|
||||||
|
@@ -90,7 +90,7 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||||
|
# machines may also. Since BFD is incredibly buggy with respect to
|
||||||
|
# crossformat linking we rely on the elf2ecoff tool for format conversion.
|
||||||
|
#
|
||||||
|
-cflags-y += -G 0 -mno-abicalls -fno-pic -pipe
|
||||||
|
+cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||||
|
cflags-y += -msoft-float
|
||||||
|
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||||
|
KBUILD_AFLAGS_MODULE += -mlong-calls
|
|
@ -0,0 +1,106 @@
|
||||||
|
From: Manuel Lauss <manuel.lauss@gmail.com>
|
||||||
|
Subject: [RFC PATCH v4 2/2] MIPS: make FPU emulator optional
|
||||||
|
Date: Mon, 7 Apr 2014 12:57:04 +0200
|
||||||
|
Message-Id: <1396868224-252888-2-git-send-email-manuel.lauss@gmail.com>
|
||||||
|
|
||||||
|
This small patch makes the MIPS FPU emulator optional. The kernel
|
||||||
|
kills float-users on systems without a hardware FPU by sending a SIGILL.
|
||||||
|
|
||||||
|
Disabling the emulator shrinks vmlinux by about 54kBytes (32bit,
|
||||||
|
optimizing for size).
|
||||||
|
|
||||||
|
Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com>
|
||||||
|
---
|
||||||
|
v4: rediffed because of patch 1/2, should now work with micromips as well
|
||||||
|
v3: updated patch description with size savings.
|
||||||
|
v2: incorporated changes suggested by Jonas Gorski
|
||||||
|
force the fpu emulator on for micromips: relocating the parts
|
||||||
|
of the mmips code in the emulator to other areas would be a
|
||||||
|
much larger change; I went the cheap route instead with this.
|
||||||
|
|
||||||
|
arch/mips/Kbuild | 2 +-
|
||||||
|
arch/mips/Kconfig | 14 ++++++++++++++
|
||||||
|
arch/mips/include/asm/fpu.h | 5 +++--
|
||||||
|
arch/mips/include/asm/fpu_emulator.h | 15 +++++++++++++++
|
||||||
|
4 files changed, 33 insertions(+), 3 deletions(-)
|
||||||
|
|
||||||
|
--- a/arch/mips/Kconfig
|
||||||
|
+++ b/arch/mips/Kconfig
|
||||||
|
@@ -2891,6 +2891,20 @@ config MIPS_O32_FP64_SUPPORT
|
||||||
|
|
||||||
|
If unsure, say N.
|
||||||
|
|
||||||
|
+config MIPS_FPU_EMULATOR
|
||||||
|
+ bool "MIPS FPU Emulator"
|
||||||
|
+ default y
|
||||||
|
+ help
|
||||||
|
+ This option lets you disable the built-in MIPS FPU (Coprocessor 1)
|
||||||
|
+ emulator, which handles floating-point instructions on processors
|
||||||
|
+ without a hardware FPU. It is generally a good idea to keep the
|
||||||
|
+ emulator built-in, unless you are perfectly sure you have a
|
||||||
|
+ complete soft-float environment. With the emulator disabled, all
|
||||||
|
+ users of float operations will be killed with an illegal instr-
|
||||||
|
+ uction exception.
|
||||||
|
+
|
||||||
|
+ Say Y, please.
|
||||||
|
+
|
||||||
|
config USE_OF
|
||||||
|
bool
|
||||||
|
select OF
|
||||||
|
--- a/arch/mips/Makefile
|
||||||
|
+++ b/arch/mips/Makefile
|
||||||
|
@@ -287,7 +287,7 @@ OBJCOPYFLAGS += --remove-section=.regin
|
||||||
|
head-y := arch/mips/kernel/head.o
|
||||||
|
|
||||||
|
libs-y += arch/mips/lib/
|
||||||
|
-libs-y += arch/mips/math-emu/
|
||||||
|
+libs-$(CONFIG_MIPS_FPU_EMULATOR) += arch/mips/math-emu/
|
||||||
|
|
||||||
|
# See arch/mips/Kbuild for content of core part of the kernel
|
||||||
|
core-y += arch/mips/
|
||||||
|
--- a/arch/mips/include/asm/fpu.h
|
||||||
|
+++ b/arch/mips/include/asm/fpu.h
|
||||||
|
@@ -227,8 +227,10 @@ static inline int init_fpu(void)
|
||||||
|
/* Restore FRE */
|
||||||
|
write_c0_config5(config5);
|
||||||
|
enable_fpu_hazard();
|
||||||
|
- } else
|
||||||
|
+ } else if (IS_ENABLED(CONFIG_MIPS_FPU_EMULATOR))
|
||||||
|
fpu_emulator_init_fpu();
|
||||||
|
+ else
|
||||||
|
+ ret = SIGILL;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
--- a/arch/mips/include/asm/fpu_emulator.h
|
||||||
|
+++ b/arch/mips/include/asm/fpu_emulator.h
|
||||||
|
@@ -30,6 +30,7 @@
|
||||||
|
#include <asm/local.h>
|
||||||
|
#include <asm/processor.h>
|
||||||
|
|
||||||
|
+#ifdef CONFIG_MIPS_FPU_EMULATOR
|
||||||
|
#ifdef CONFIG_DEBUG_FS
|
||||||
|
|
||||||
|
struct mips_fpu_emulator_stats {
|
||||||
|
@@ -63,6 +64,21 @@ do { \
|
||||||
|
extern int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||||
|
struct mips_fpu_struct *ctx, int has_fpu,
|
||||||
|
void *__user *fault_addr);
|
||||||
|
+#else /* no CONFIG_MIPS_FPU_EMULATOR */
|
||||||
|
+static inline int do_dsemulret(struct pt_regs *xcp)
|
||||||
|
+{
|
||||||
|
+ return 0; /* 0 means error, should never get here anyway */
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline int fpu_emulator_cop1Handler(struct pt_regs *xcp,
|
||||||
|
+ struct mips_fpu_struct *ctx, int has_fpu,
|
||||||
|
+ void *__user *fault_addr)
|
||||||
|
+{
|
||||||
|
+ *fault_addr = NULL;
|
||||||
|
+ return SIGILL; /* we don't speak MIPS FPU */
|
||||||
|
+}
|
||||||
|
+#endif /* CONFIG_MIPS_FPU_EMULATOR */
|
||||||
|
+
|
||||||
|
void force_fcr31_sig(unsigned long fcr31, void __user *fault_addr,
|
||||||
|
struct task_struct *tsk);
|
||||||
|
int process_fpemu_return(int sig, void __user *fault_addr,
|
|
@ -0,0 +1,351 @@
|
||||||
|
--- a/arch/mips/Makefile
|
||||||
|
+++ b/arch/mips/Makefile
|
||||||
|
@@ -93,8 +93,13 @@ all-$(CONFIG_SYS_SUPPORTS_ZBOOT)+= vmlin
|
||||||
|
cflags-y += -G 0 -mno-abicalls -fno-pic -pipe -mno-branch-likely
|
||||||
|
cflags-y += -msoft-float
|
||||||
|
LDFLAGS_vmlinux += -G 0 -static -n -nostdlib
|
||||||
|
+ifdef CONFIG_64BIT
|
||||||
|
KBUILD_AFLAGS_MODULE += -mlong-calls
|
||||||
|
KBUILD_CFLAGS_MODULE += -mlong-calls
|
||||||
|
+else
|
||||||
|
+KBUILD_AFLAGS_MODULE += -mno-long-calls
|
||||||
|
+KBUILD_CFLAGS_MODULE += -mno-long-calls
|
||||||
|
+endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_RELOCATABLE),y)
|
||||||
|
LDFLAGS_vmlinux += --emit-relocs
|
||||||
|
--- a/arch/mips/include/asm/module.h
|
||||||
|
+++ b/arch/mips/include/asm/module.h
|
||||||
|
@@ -11,6 +11,11 @@ struct mod_arch_specific {
|
||||||
|
const struct exception_table_entry *dbe_start;
|
||||||
|
const struct exception_table_entry *dbe_end;
|
||||||
|
struct mips_hi16 *r_mips_hi16_list;
|
||||||
|
+
|
||||||
|
+ void *phys_plt_tbl;
|
||||||
|
+ void *virt_plt_tbl;
|
||||||
|
+ unsigned int phys_plt_offset;
|
||||||
|
+ unsigned int virt_plt_offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef uint8_t Elf64_Byte; /* Type for a 8-bit quantity. */
|
||||||
|
--- a/arch/mips/kernel/module.c
|
||||||
|
+++ b/arch/mips/kernel/module.c
|
||||||
|
@@ -44,14 +44,221 @@ struct mips_hi16 {
|
||||||
|
static LIST_HEAD(dbe_list);
|
||||||
|
static DEFINE_SPINLOCK(dbe_lock);
|
||||||
|
|
||||||
|
-#ifdef MODULE_START
|
||||||
|
+/*
|
||||||
|
+ * Get the potential max trampolines size required of the init and
|
||||||
|
+ * non-init sections. Only used if we cannot find enough contiguous
|
||||||
|
+ * physically mapped memory to put the module into.
|
||||||
|
+ */
|
||||||
|
+static unsigned int
|
||||||
|
+get_plt_size(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
|
||||||
|
+ const char *secstrings, unsigned int symindex, bool is_init)
|
||||||
|
+{
|
||||||
|
+ unsigned long ret = 0;
|
||||||
|
+ unsigned int i, j;
|
||||||
|
+ Elf_Sym *syms;
|
||||||
|
+
|
||||||
|
+ /* Everything marked ALLOC (this includes the exported symbols) */
|
||||||
|
+ for (i = 1; i < hdr->e_shnum; ++i) {
|
||||||
|
+ unsigned int info = sechdrs[i].sh_info;
|
||||||
|
+
|
||||||
|
+ if (sechdrs[i].sh_type != SHT_REL
|
||||||
|
+ && sechdrs[i].sh_type != SHT_RELA)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ /* Not a valid relocation section? */
|
||||||
|
+ if (info >= hdr->e_shnum)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ /* Don't bother with non-allocated sections */
|
||||||
|
+ if (!(sechdrs[info].sh_flags & SHF_ALLOC))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ /* If it's called *.init*, and we're not init, we're
|
||||||
|
+ not interested */
|
||||||
|
+ if ((strstr(secstrings + sechdrs[i].sh_name, ".init") != 0)
|
||||||
|
+ != is_init)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ syms = (Elf_Sym *) sechdrs[symindex].sh_addr;
|
||||||
|
+ if (sechdrs[i].sh_type == SHT_REL) {
|
||||||
|
+ Elf_Mips_Rel *rel = (void *) sechdrs[i].sh_addr;
|
||||||
|
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rel);
|
||||||
|
+
|
||||||
|
+ for (j = 0; j < size; ++j) {
|
||||||
|
+ Elf_Sym *sym;
|
||||||
|
+
|
||||||
|
+ if (ELF_MIPS_R_TYPE(rel[j]) != R_MIPS_26)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ sym = syms + ELF_MIPS_R_SYM(rel[j]);
|
||||||
|
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ ret += 4 * sizeof(int);
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ Elf_Mips_Rela *rela = (void *) sechdrs[i].sh_addr;
|
||||||
|
+ unsigned int size = sechdrs[i].sh_size / sizeof(*rela);
|
||||||
|
+
|
||||||
|
+ for (j = 0; j < size; ++j) {
|
||||||
|
+ Elf_Sym *sym;
|
||||||
|
+
|
||||||
|
+ if (ELF_MIPS_R_TYPE(rela[j]) != R_MIPS_26)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ sym = syms + ELF_MIPS_R_SYM(rela[j]);
|
||||||
|
+ if (!is_init && sym->st_shndx != SHN_UNDEF)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ ret += 4 * sizeof(int);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+#ifndef MODULE_START
|
||||||
|
+static void *alloc_phys(unsigned long size)
|
||||||
|
+{
|
||||||
|
+ unsigned order;
|
||||||
|
+ struct page *page;
|
||||||
|
+ struct page *p;
|
||||||
|
+
|
||||||
|
+ size = PAGE_ALIGN(size);
|
||||||
|
+ order = get_order(size);
|
||||||
|
+
|
||||||
|
+ page = alloc_pages(GFP_KERNEL | __GFP_NORETRY | __GFP_NOWARN |
|
||||||
|
+ __GFP_THISNODE, order);
|
||||||
|
+ if (!page)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ split_page(page, order);
|
||||||
|
+
|
||||||
|
+ /* mark all pages except for the last one */
|
||||||
|
+ for (p = page; p + 1 < page + (size >> PAGE_SHIFT); ++p)
|
||||||
|
+ set_bit(PG_owner_priv_1, &p->flags);
|
||||||
|
+
|
||||||
|
+ for (p = page + (size >> PAGE_SHIFT); p < page + (1 << order); ++p)
|
||||||
|
+ __free_page(p);
|
||||||
|
+
|
||||||
|
+ return page_address(page);
|
||||||
|
+}
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static void free_phys(void *ptr)
|
||||||
|
+{
|
||||||
|
+ struct page *page;
|
||||||
|
+ bool free;
|
||||||
|
+
|
||||||
|
+ page = virt_to_page(ptr);
|
||||||
|
+ do {
|
||||||
|
+ free = test_and_clear_bit(PG_owner_priv_1, &page->flags);
|
||||||
|
+ __free_page(page);
|
||||||
|
+ page++;
|
||||||
|
+ } while (free);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+
|
||||||
|
void *module_alloc(unsigned long size)
|
||||||
|
{
|
||||||
|
+#ifdef MODULE_START
|
||||||
|
return __vmalloc_node_range(size, 1, MODULE_START, MODULE_END,
|
||||||
|
GFP_KERNEL, PAGE_KERNEL, 0, NUMA_NO_NODE,
|
||||||
|
__builtin_return_address(0));
|
||||||
|
+#else
|
||||||
|
+ void *ptr;
|
||||||
|
+
|
||||||
|
+ if (size == 0)
|
||||||
|
+ return NULL;
|
||||||
|
+
|
||||||
|
+ ptr = alloc_phys(size);
|
||||||
|
+
|
||||||
|
+ /* If we failed to allocate physically contiguous memory,
|
||||||
|
+ * fall back to regular vmalloc. The module loader code will
|
||||||
|
+ * create jump tables to handle long jumps */
|
||||||
|
+ if (!ptr)
|
||||||
|
+ return vmalloc(size);
|
||||||
|
+
|
||||||
|
+ return ptr;
|
||||||
|
+#endif
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+static inline bool is_phys_addr(void *ptr)
|
||||||
|
+{
|
||||||
|
+#ifdef CONFIG_64BIT
|
||||||
|
+ return (KSEGX((unsigned long)ptr) == CKSEG0);
|
||||||
|
+#else
|
||||||
|
+ return (KSEGX(ptr) == KSEG0);
|
||||||
|
#endif
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+/* Free memory returned from module_alloc */
|
||||||
|
+void module_memfree(void *module_region)
|
||||||
|
+{
|
||||||
|
+ if (is_phys_addr(module_region))
|
||||||
|
+ free_phys(module_region);
|
||||||
|
+ else
|
||||||
|
+ vfree(module_region);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void *__module_alloc(int size, bool phys)
|
||||||
|
+{
|
||||||
|
+ void *ptr;
|
||||||
|
+
|
||||||
|
+ if (phys)
|
||||||
|
+ ptr = kmalloc(size, GFP_KERNEL);
|
||||||
|
+ else
|
||||||
|
+ ptr = vmalloc(size);
|
||||||
|
+ return ptr;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void __module_free(void *ptr)
|
||||||
|
+{
|
||||||
|
+ if (is_phys_addr(ptr))
|
||||||
|
+ kfree(ptr);
|
||||||
|
+ else
|
||||||
|
+ vfree(ptr);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs,
|
||||||
|
+ char *secstrings, struct module *mod)
|
||||||
|
+{
|
||||||
|
+ unsigned int symindex = 0;
|
||||||
|
+ unsigned int core_size, init_size;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ mod->arch.phys_plt_offset = 0;
|
||||||
|
+ mod->arch.virt_plt_offset = 0;
|
||||||
|
+ mod->arch.phys_plt_tbl = NULL;
|
||||||
|
+ mod->arch.virt_plt_tbl = NULL;
|
||||||
|
+
|
||||||
|
+ if (IS_ENABLED(CONFIG_64BIT))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ for (i = 1; i < hdr->e_shnum; i++)
|
||||||
|
+ if (sechdrs[i].sh_type == SHT_SYMTAB)
|
||||||
|
+ symindex = i;
|
||||||
|
+
|
||||||
|
+ core_size = get_plt_size(hdr, sechdrs, secstrings, symindex, false);
|
||||||
|
+ init_size = get_plt_size(hdr, sechdrs, secstrings, symindex, true);
|
||||||
|
+
|
||||||
|
+ if ((core_size + init_size) == 0)
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ mod->arch.phys_plt_tbl = __module_alloc(core_size + init_size, 1);
|
||||||
|
+ if (!mod->arch.phys_plt_tbl)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ mod->arch.virt_plt_tbl = __module_alloc(core_size + init_size, 0);
|
||||||
|
+ if (!mod->arch.virt_plt_tbl) {
|
||||||
|
+ __module_free(mod->arch.phys_plt_tbl);
|
||||||
|
+ mod->arch.phys_plt_tbl = NULL;
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return 0;
|
||||||
|
+}
|
||||||
|
|
||||||
|
int apply_r_mips_none(struct module *me, u32 *location, Elf_Addr v)
|
||||||
|
{
|
||||||
|
@@ -65,8 +272,39 @@ static int apply_r_mips_32_rel(struct mo
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static Elf_Addr add_plt_entry_to(unsigned *plt_offset,
|
||||||
|
+ void *start, Elf_Addr v)
|
||||||
|
+{
|
||||||
|
+ unsigned *tramp = start + *plt_offset;
|
||||||
|
+ *plt_offset += 4 * sizeof(int);
|
||||||
|
+
|
||||||
|
+ /* adjust carry for addiu */
|
||||||
|
+ if (v & 0x00008000)
|
||||||
|
+ v += 0x10000;
|
||||||
|
+
|
||||||
|
+ tramp[0] = 0x3c190000 | (v >> 16); /* lui t9, hi16 */
|
||||||
|
+ tramp[1] = 0x27390000 | (v & 0xffff); /* addiu t9, t9, lo16 */
|
||||||
|
+ tramp[2] = 0x03200008; /* jr t9 */
|
||||||
|
+ tramp[3] = 0x00000000; /* nop */
|
||||||
|
+
|
||||||
|
+ return (Elf_Addr) tramp;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static Elf_Addr add_plt_entry(struct module *me, void *location, Elf_Addr v)
|
||||||
|
+{
|
||||||
|
+ if (is_phys_addr(location))
|
||||||
|
+ return add_plt_entry_to(&me->arch.phys_plt_offset,
|
||||||
|
+ me->arch.phys_plt_tbl, v);
|
||||||
|
+ else
|
||||||
|
+ return add_plt_entry_to(&me->arch.virt_plt_offset,
|
||||||
|
+ me->arch.virt_plt_tbl, v);
|
||||||
|
+
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static int apply_r_mips_26_rel(struct module *me, u32 *location, Elf_Addr v)
|
||||||
|
{
|
||||||
|
+ u32 ofs = *location & 0x03ffffff;
|
||||||
|
+
|
||||||
|
if (v % 4) {
|
||||||
|
pr_err("module %s: dangerous R_MIPS_26 REL relocation\n",
|
||||||
|
me->name);
|
||||||
|
@@ -74,13 +312,17 @@ static int apply_r_mips_26_rel(struct mo
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((v & 0xf0000000) != (((unsigned long)location + 4) & 0xf0000000)) {
|
||||||
|
- pr_err("module %s: relocation overflow\n",
|
||||||
|
- me->name);
|
||||||
|
- return -ENOEXEC;
|
||||||
|
+ v = add_plt_entry(me, location, v + (ofs << 2));
|
||||||
|
+ if (!v) {
|
||||||
|
+ pr_err("module %s: relocation overflow\n",
|
||||||
|
+ me->name);
|
||||||
|
+ return -ENOEXEC;
|
||||||
|
+ }
|
||||||
|
+ ofs = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
*location = (*location & ~0x03ffffff) |
|
||||||
|
- ((*location + (v >> 2)) & 0x03ffffff);
|
||||||
|
+ ((ofs + (v >> 2)) & 0x03ffffff);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@@ -349,9 +591,33 @@ int module_finalize(const Elf_Ehdr *hdr,
|
||||||
|
list_add(&me->arch.dbe_list, &dbe_list);
|
||||||
|
spin_unlock_irq(&dbe_lock);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ /* Get rid of the fixup trampoline if we're running the module
|
||||||
|
+ * from physically mapped address space */
|
||||||
|
+ if (me->arch.phys_plt_offset == 0) {
|
||||||
|
+ __module_free(me->arch.phys_plt_tbl);
|
||||||
|
+ me->arch.phys_plt_tbl = NULL;
|
||||||
|
+ }
|
||||||
|
+ if (me->arch.virt_plt_offset == 0) {
|
||||||
|
+ __module_free(me->arch.virt_plt_tbl);
|
||||||
|
+ me->arch.virt_plt_tbl = NULL;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+void module_arch_freeing_init(struct module *mod)
|
||||||
|
+{
|
||||||
|
+ if (mod->arch.phys_plt_tbl) {
|
||||||
|
+ __module_free(mod->arch.phys_plt_tbl);
|
||||||
|
+ mod->arch.phys_plt_tbl = NULL;
|
||||||
|
+ }
|
||||||
|
+ if (mod->arch.virt_plt_tbl) {
|
||||||
|
+ __module_free(mod->arch.virt_plt_tbl);
|
||||||
|
+ mod->arch.virt_plt_tbl = NULL;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void module_arch_cleanup(struct module *mod)
|
||||||
|
{
|
||||||
|
spin_lock_irq(&dbe_lock);
|
|
@ -0,0 +1,83 @@
|
||||||
|
--- a/arch/mips/include/asm/string.h
|
||||||
|
+++ b/arch/mips/include/asm/string.h
|
||||||
|
@@ -133,11 +133,44 @@ strncmp(__const__ char *__cs, __const__
|
||||||
|
|
||||||
|
#define __HAVE_ARCH_MEMSET
|
||||||
|
extern void *memset(void *__s, int __c, size_t __count);
|
||||||
|
+#define memset(__s, __c, len) \
|
||||||
|
+({ \
|
||||||
|
+ size_t __len = (len); \
|
||||||
|
+ void *__ret; \
|
||||||
|
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||||
|
+ __ret = memset((__s), (__c), __len); \
|
||||||
|
+ else \
|
||||||
|
+ __ret = __builtin_memset((__s), (__c), __len); \
|
||||||
|
+ __ret; \
|
||||||
|
+})
|
||||||
|
|
||||||
|
#define __HAVE_ARCH_MEMCPY
|
||||||
|
extern void *memcpy(void *__to, __const__ void *__from, size_t __n);
|
||||||
|
+#define memcpy(dst, src, len) \
|
||||||
|
+({ \
|
||||||
|
+ size_t __len = (len); \
|
||||||
|
+ void *__ret; \
|
||||||
|
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||||
|
+ __ret = memcpy((dst), (src), __len); \
|
||||||
|
+ else \
|
||||||
|
+ __ret = __builtin_memcpy((dst), (src), __len); \
|
||||||
|
+ __ret; \
|
||||||
|
+})
|
||||||
|
|
||||||
|
#define __HAVE_ARCH_MEMMOVE
|
||||||
|
extern void *memmove(void *__dest, __const__ void *__src, size_t __n);
|
||||||
|
+#define memmove(dst, src, len) \
|
||||||
|
+({ \
|
||||||
|
+ size_t __len = (len); \
|
||||||
|
+ void *__ret; \
|
||||||
|
+ if (__builtin_constant_p(len) && __len >= 64) \
|
||||||
|
+ __ret = memmove((dst), (src), __len); \
|
||||||
|
+ else \
|
||||||
|
+ __ret = __builtin_memmove((dst), (src), __len); \
|
||||||
|
+ __ret; \
|
||||||
|
+})
|
||||||
|
+
|
||||||
|
+#define __HAVE_ARCH_MEMCMP
|
||||||
|
+#define memcmp(src1, src2, len) __builtin_memcmp((src1), (src2), (len))
|
||||||
|
|
||||||
|
#endif /* _ASM_STRING_H */
|
||||||
|
--- a/arch/mips/lib/Makefile
|
||||||
|
+++ b/arch/mips/lib/Makefile
|
||||||
|
@@ -4,7 +4,7 @@
|
||||||
|
|
||||||
|
lib-y += bitops.o csum_partial.o delay.o memcpy.o memset.o \
|
||||||
|
mips-atomic.o strlen_user.o strncpy_user.o \
|
||||||
|
- strnlen_user.o uncached.o
|
||||||
|
+ strnlen_user.o uncached.o memcmp.o
|
||||||
|
|
||||||
|
obj-y += iomap.o
|
||||||
|
obj-$(CONFIG_PCI) += iomap-pci.o
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/mips/lib/memcmp.c
|
||||||
|
@@ -0,0 +1,22 @@
|
||||||
|
+/*
|
||||||
|
+ * copied from linux/lib/string.c
|
||||||
|
+ *
|
||||||
|
+ * Copyright (C) 1991, 1992 Linus Torvalds
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+#include <linux/module.h>
|
||||||
|
+#include <linux/string.h>
|
||||||
|
+
|
||||||
|
+#undef memcmp
|
||||||
|
+int memcmp(const void *cs, const void *ct, size_t count)
|
||||||
|
+{
|
||||||
|
+ const unsigned char *su1, *su2;
|
||||||
|
+ int res = 0;
|
||||||
|
+
|
||||||
|
+ for (su1 = cs, su2 = ct; 0 < count; ++su1, ++su2, count--)
|
||||||
|
+ if ((res = *su1 - *su2) != 0)
|
||||||
|
+ break;
|
||||||
|
+ return res;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL(memcmp);
|
||||||
|
+
|
|
@ -0,0 +1,17 @@
|
||||||
|
Adjust highmem offset to 0x10000000 to ensure that all kmalloc allocations
|
||||||
|
stay within the same 256M boundary. This ensures that -mlong-calls is not
|
||||||
|
needed on systems with more than 256M RAM.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
---
|
||||||
|
--- a/arch/mips/include/asm/mach-generic/spaces.h
|
||||||
|
+++ b/arch/mips/include/asm/mach-generic/spaces.h
|
||||||
|
@@ -46,7 +46,7 @@
|
||||||
|
* Memory above this physical address will be considered highmem.
|
||||||
|
*/
|
||||||
|
#ifndef HIGHMEM_START
|
||||||
|
-#define HIGHMEM_START _AC(0x20000000, UL)
|
||||||
|
+#define HIGHMEM_START _AC(0x10000000, UL)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* CONFIG_32BIT */
|
|
@ -0,0 +1,17 @@
|
||||||
|
Add -mtune=34kc to MIPS CFLAGS when building for mips32r2
|
||||||
|
This provides a good tradeoff across at least 24Kc-74Kc, while also
|
||||||
|
producing smaller code.
|
||||||
|
|
||||||
|
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||||
|
|
||||||
|
--- a/arch/mips/Makefile
|
||||||
|
+++ b/arch/mips/Makefile
|
||||||
|
@@ -148,7 +148,7 @@ cflags-$(CONFIG_CPU_R4X00) += -march=r46
|
||||||
|
cflags-$(CONFIG_CPU_TX49XX) += -march=r4600 -Wa,--trap
|
||||||
|
cflags-$(CONFIG_CPU_MIPS32_R1) += $(call cc-option,-march=mips32,-mips32 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||||
|
-Wa,-mips32 -Wa,--trap
|
||||||
|
-cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||||
|
+cflags-$(CONFIG_CPU_MIPS32_R2) += $(call cc-option,-march=mips32r2 -mtune=34kc,-mips32r2 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS32) \
|
||||||
|
-Wa,-mips32r2 -Wa,--trap
|
||||||
|
cflags-$(CONFIG_CPU_MIPS32_R6) += -march=mips32r6 -Wa,--trap
|
||||||
|
cflags-$(CONFIG_CPU_MIPS64_R1) += $(call cc-option,-march=mips64,-mips64 -U_MIPS_ISA -D_MIPS_ISA=_MIPS_ISA_MIPS64) \
|
|
@ -0,0 +1,13 @@
|
||||||
|
--- a/arch/arm/kernel/module.c
|
||||||
|
+++ b/arch/arm/kernel/module.c
|
||||||
|
@@ -88,6 +88,10 @@ apply_relocate(Elf32_Shdr *sechdrs, cons
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if ((IS_ERR_VALUE(sym->st_value) || !sym->st_value) &&
|
||||||
|
+ ELF_ST_BIND(sym->st_info) == STB_WEAK)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
loc = dstsec->sh_addr + rel->r_offset;
|
||||||
|
|
||||||
|
switch (ELF32_R_TYPE(rel->r_info)) {
|
|
@ -0,0 +1,10 @@
|
||||||
|
--- a/arch/powerpc/Makefile
|
||||||
|
+++ b/arch/powerpc/Makefile
|
||||||
|
@@ -179,7 +179,6 @@ else
|
||||||
|
CHECKFLAGS += -D__LITTLE_ENDIAN__
|
||||||
|
endif
|
||||||
|
|
||||||
|
-KBUILD_LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_476FPE_ERR46),y)
|
||||||
|
KBUILD_LDFLAGS_MODULE += --ppc476-workaround \
|
|
@ -0,0 +1,272 @@
|
||||||
|
From d8582dcf1ed66eee88a11e4760f42c0d6c8822be Mon Sep 17 00:00:00 2001
|
||||||
|
From: Yousong Zhou <yszhou4tech@gmail.com>
|
||||||
|
Date: Sat, 31 Jan 2015 22:26:03 +0800
|
||||||
|
Subject: [PATCH 331/331] MIPS: kexec: Accept command line parameters from
|
||||||
|
userspace.
|
||||||
|
|
||||||
|
Signed-off-by: Yousong Zhou <yszhou4tech@gmail.com>
|
||||||
|
---
|
||||||
|
arch/mips/kernel/machine_kexec.c | 153 +++++++++++++++++++++++++++++++-----
|
||||||
|
arch/mips/kernel/machine_kexec.h | 20 +++++
|
||||||
|
arch/mips/kernel/relocate_kernel.S | 21 +++--
|
||||||
|
3 files changed, 167 insertions(+), 27 deletions(-)
|
||||||
|
create mode 100644 arch/mips/kernel/machine_kexec.h
|
||||||
|
|
||||||
|
--- a/arch/mips/kernel/machine_kexec.c
|
||||||
|
+++ b/arch/mips/kernel/machine_kexec.c
|
||||||
|
@@ -10,14 +10,11 @@
|
||||||
|
#include <linux/mm.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
|
+#include <asm/bootinfo.h>
|
||||||
|
#include <asm/cacheflush.h>
|
||||||
|
#include <asm/page.h>
|
||||||
|
-
|
||||||
|
-extern const unsigned char relocate_new_kernel[];
|
||||||
|
-extern const size_t relocate_new_kernel_size;
|
||||||
|
-
|
||||||
|
-extern unsigned long kexec_start_address;
|
||||||
|
-extern unsigned long kexec_indirection_page;
|
||||||
|
+#include <asm/uaccess.h>
|
||||||
|
+#include "machine_kexec.h"
|
||||||
|
|
||||||
|
int (*_machine_kexec_prepare)(struct kimage *) = NULL;
|
||||||
|
void (*_machine_kexec_shutdown)(void) = NULL;
|
||||||
|
@@ -28,9 +25,115 @@ atomic_t kexec_ready_to_reboot = ATOMIC_
|
||||||
|
void (*_crash_smp_send_stop)(void) = NULL;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
+static void machine_kexec_print_args(void)
|
||||||
|
+{
|
||||||
|
+ unsigned long argc = (int)kexec_args[0];
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ pr_info("kexec_args[0] (argc): %lu\n", argc);
|
||||||
|
+ pr_info("kexec_args[1] (argv): %p\n", (void *)kexec_args[1]);
|
||||||
|
+ pr_info("kexec_args[2] (env ): %p\n", (void *)kexec_args[2]);
|
||||||
|
+ pr_info("kexec_args[3] (desc): %p\n", (void *)kexec_args[3]);
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < argc; i++) {
|
||||||
|
+ pr_info("kexec_argv[%d] = %p, %s\n",
|
||||||
|
+ i, kexec_argv[i], kexec_argv[i]);
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void machine_kexec_init_argv(struct kimage *image)
|
||||||
|
+{
|
||||||
|
+ void __user *buf = NULL;
|
||||||
|
+ size_t bufsz;
|
||||||
|
+ size_t size;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ bufsz = 0;
|
||||||
|
+ for (i = 0; i < image->nr_segments; i++) {
|
||||||
|
+ struct kexec_segment *seg;
|
||||||
|
+
|
||||||
|
+ seg = &image->segment[i];
|
||||||
|
+ if (seg->bufsz < 6)
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ if (strncmp((char *) seg->buf, "kexec ", 6))
|
||||||
|
+ continue;
|
||||||
|
+
|
||||||
|
+ buf = seg->buf;
|
||||||
|
+ bufsz = seg->bufsz;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!buf)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ size = KEXEC_COMMAND_LINE_SIZE;
|
||||||
|
+ size = min(size, bufsz);
|
||||||
|
+ if (size < bufsz)
|
||||||
|
+ pr_warn("kexec command line truncated to %zd bytes\n", size);
|
||||||
|
+
|
||||||
|
+ /* Copy to kernel space */
|
||||||
|
+ copy_from_user(kexec_argv_buf, buf, size);
|
||||||
|
+ kexec_argv_buf[size - 1] = 0;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void machine_kexec_parse_argv(struct kimage *image)
|
||||||
|
+{
|
||||||
|
+ char *reboot_code_buffer;
|
||||||
|
+ int reloc_delta;
|
||||||
|
+ char *ptr;
|
||||||
|
+ int argc;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ ptr = kexec_argv_buf;
|
||||||
|
+ argc = 0;
|
||||||
|
+
|
||||||
|
+ /*
|
||||||
|
+ * convert command line string to array of parameters
|
||||||
|
+ * (as bootloader does).
|
||||||
|
+ */
|
||||||
|
+ while (ptr && *ptr && (KEXEC_MAX_ARGC > argc)) {
|
||||||
|
+ if (*ptr == ' ') {
|
||||||
|
+ *ptr++ = '\0';
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ kexec_argv[argc++] = ptr;
|
||||||
|
+ ptr = strchr(ptr, ' ');
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ if (!argc)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ kexec_args[0] = argc;
|
||||||
|
+ kexec_args[1] = (unsigned long)kexec_argv;
|
||||||
|
+ kexec_args[2] = 0;
|
||||||
|
+ kexec_args[3] = 0;
|
||||||
|
+
|
||||||
|
+ reboot_code_buffer = page_address(image->control_code_page);
|
||||||
|
+ reloc_delta = reboot_code_buffer - (char *)kexec_relocate_new_kernel;
|
||||||
|
+
|
||||||
|
+ kexec_args[1] += reloc_delta;
|
||||||
|
+ for (i = 0; i < argc; i++)
|
||||||
|
+ kexec_argv[i] += reloc_delta;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
int
|
||||||
|
machine_kexec_prepare(struct kimage *kimage)
|
||||||
|
{
|
||||||
|
+ /*
|
||||||
|
+ * Whenever arguments passed from kexec-tools, Init the arguments as
|
||||||
|
+ * the original ones to try avoiding booting failure.
|
||||||
|
+ */
|
||||||
|
+
|
||||||
|
+ kexec_args[0] = fw_arg0;
|
||||||
|
+ kexec_args[1] = fw_arg1;
|
||||||
|
+ kexec_args[2] = fw_arg2;
|
||||||
|
+ kexec_args[3] = fw_arg3;
|
||||||
|
+
|
||||||
|
+ machine_kexec_init_argv(kimage);
|
||||||
|
+ machine_kexec_parse_argv(kimage);
|
||||||
|
+
|
||||||
|
if (_machine_kexec_prepare)
|
||||||
|
return _machine_kexec_prepare(kimage);
|
||||||
|
return 0;
|
||||||
|
@@ -67,10 +170,12 @@ machine_kexec(struct kimage *image)
|
||||||
|
unsigned long *ptr;
|
||||||
|
|
||||||
|
reboot_code_buffer =
|
||||||
|
- (unsigned long)page_address(image->control_code_page);
|
||||||
|
+ (unsigned long)page_address(image->control_code_page);
|
||||||
|
+ pr_info("reboot_code_buffer = %p\n", (void *)reboot_code_buffer);
|
||||||
|
|
||||||
|
kexec_start_address =
|
||||||
|
(unsigned long) phys_to_virt(image->start);
|
||||||
|
+ pr_info("kexec_start_address = %p\n", (void *)kexec_start_address);
|
||||||
|
|
||||||
|
if (image->type == KEXEC_TYPE_DEFAULT) {
|
||||||
|
kexec_indirection_page =
|
||||||
|
@@ -78,9 +183,19 @@ machine_kexec(struct kimage *image)
|
||||||
|
} else {
|
||||||
|
kexec_indirection_page = (unsigned long)&image->head;
|
||||||
|
}
|
||||||
|
+ pr_info("kexec_indirection_page = %p\n", (void *)kexec_indirection_page);
|
||||||
|
|
||||||
|
- memcpy((void*)reboot_code_buffer, relocate_new_kernel,
|
||||||
|
- relocate_new_kernel_size);
|
||||||
|
+ pr_info("Where is memcpy: %p\n", memcpy);
|
||||||
|
+ pr_info("kexec_relocate_new_kernel = %p, kexec_relocate_new_kernel_end = %p\n",
|
||||||
|
+ (void *)kexec_relocate_new_kernel, &kexec_relocate_new_kernel_end);
|
||||||
|
+ pr_info("Copy %lu bytes from %p to %p\n", KEXEC_RELOCATE_NEW_KERNEL_SIZE,
|
||||||
|
+ (void *)kexec_relocate_new_kernel, (void *)reboot_code_buffer);
|
||||||
|
+ memcpy((void*)reboot_code_buffer, kexec_relocate_new_kernel,
|
||||||
|
+ KEXEC_RELOCATE_NEW_KERNEL_SIZE);
|
||||||
|
+
|
||||||
|
+ pr_info("Before _print_args().\n");
|
||||||
|
+ machine_kexec_print_args();
|
||||||
|
+ pr_info("Before eval loop.\n");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The generic kexec code builds a page list with physical
|
||||||
|
@@ -99,15 +214,16 @@ machine_kexec(struct kimage *image)
|
||||||
|
/*
|
||||||
|
* we do not want to be bothered.
|
||||||
|
*/
|
||||||
|
+ pr_info("Before irq_disable.\n");
|
||||||
|
local_irq_disable();
|
||||||
|
|
||||||
|
- printk("Will call new kernel at %08lx\n", image->start);
|
||||||
|
- printk("Bye ...\n");
|
||||||
|
+ pr_info("Will call new kernel at %08lx\n", image->start);
|
||||||
|
+ pr_info("Bye ...\n");
|
||||||
|
__flush_cache_all();
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/* All secondary cpus now may jump to kexec_wait cycle */
|
||||||
|
relocated_kexec_smp_wait = reboot_code_buffer +
|
||||||
|
- (void *)(kexec_smp_wait - relocate_new_kernel);
|
||||||
|
+ (void *)(kexec_smp_wait - kexec_relocate_new_kernel);
|
||||||
|
smp_wmb();
|
||||||
|
atomic_set(&kexec_ready_to_reboot, 1);
|
||||||
|
#endif
|
||||||
|
--- /dev/null
|
||||||
|
+++ b/arch/mips/kernel/machine_kexec.h
|
||||||
|
@@ -0,0 +1,20 @@
|
||||||
|
+#ifndef _MACHINE_KEXEC_H
|
||||||
|
+#define _MACHINE_KEXEC_H
|
||||||
|
+
|
||||||
|
+#ifndef __ASSEMBLY__
|
||||||
|
+extern const unsigned char kexec_relocate_new_kernel[];
|
||||||
|
+extern unsigned long kexec_relocate_new_kernel_end;
|
||||||
|
+extern unsigned long kexec_start_address;
|
||||||
|
+extern unsigned long kexec_indirection_page;
|
||||||
|
+
|
||||||
|
+extern char kexec_argv_buf[];
|
||||||
|
+extern char *kexec_argv[];
|
||||||
|
+
|
||||||
|
+#define KEXEC_RELOCATE_NEW_KERNEL_SIZE ((unsigned long)&kexec_relocate_new_kernel_end - (unsigned long)kexec_relocate_new_kernel)
|
||||||
|
+#endif /* !__ASSEMBLY__ */
|
||||||
|
+
|
||||||
|
+#define KEXEC_COMMAND_LINE_SIZE 256
|
||||||
|
+#define KEXEC_ARGV_SIZE (KEXEC_COMMAND_LINE_SIZE / 16)
|
||||||
|
+#define KEXEC_MAX_ARGC (KEXEC_ARGV_SIZE / sizeof(long))
|
||||||
|
+
|
||||||
|
+#endif
|
||||||
|
--- a/arch/mips/kernel/relocate_kernel.S
|
||||||
|
+++ b/arch/mips/kernel/relocate_kernel.S
|
||||||
|
@@ -12,8 +12,9 @@
|
||||||
|
#include <asm/mipsregs.h>
|
||||||
|
#include <asm/stackframe.h>
|
||||||
|
#include <asm/addrspace.h>
|
||||||
|
+#include "machine_kexec.h"
|
||||||
|
|
||||||
|
-LEAF(relocate_new_kernel)
|
||||||
|
+LEAF(kexec_relocate_new_kernel)
|
||||||
|
PTR_L a0, arg0
|
||||||
|
PTR_L a1, arg1
|
||||||
|
PTR_L a2, arg2
|
||||||
|
@@ -98,7 +99,7 @@ done:
|
||||||
|
#endif
|
||||||
|
/* jump to kexec_start_address */
|
||||||
|
j s1
|
||||||
|
- END(relocate_new_kernel)
|
||||||
|
+ END(kexec_relocate_new_kernel)
|
||||||
|
|
||||||
|
#ifdef CONFIG_SMP
|
||||||
|
/*
|
||||||
|
@@ -184,9 +185,15 @@ kexec_indirection_page:
|
||||||
|
PTR 0
|
||||||
|
.size kexec_indirection_page, PTRSIZE
|
||||||
|
|
||||||
|
-relocate_new_kernel_end:
|
||||||
|
+kexec_argv_buf:
|
||||||
|
+ EXPORT(kexec_argv_buf)
|
||||||
|
+ .skip KEXEC_COMMAND_LINE_SIZE
|
||||||
|
+ .size kexec_argv_buf, KEXEC_COMMAND_LINE_SIZE
|
||||||
|
+
|
||||||
|
+kexec_argv:
|
||||||
|
+ EXPORT(kexec_argv)
|
||||||
|
+ .skip KEXEC_ARGV_SIZE
|
||||||
|
+ .size kexec_argv, KEXEC_ARGV_SIZE
|
||||||
|
|
||||||
|
-relocate_new_kernel_size:
|
||||||
|
- EXPORT(relocate_new_kernel_size)
|
||||||
|
- PTR relocate_new_kernel_end - relocate_new_kernel
|
||||||
|
- .size relocate_new_kernel_size, PTRSIZE
|
||||||
|
+kexec_relocate_new_kernel_end:
|
||||||
|
+ EXPORT(kexec_relocate_new_kernel_end)
|
|
@ -0,0 +1,82 @@
|
||||||
|
From 690e7f2cad271595ff68cace1c45fb10779bde41 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||||
|
Date: Fri, 15 Jan 2016 00:34:01 +0300
|
||||||
|
Subject: [PATCH 2/2] openwrt: arc - add OWRTDTB section
|
||||||
|
|
||||||
|
This change allows OpenWRT to patch resulting kernel binary with
|
||||||
|
external .dtb.
|
||||||
|
|
||||||
|
That allows us to re-use exactky the same vmlinux on different boards
|
||||||
|
given its ARC core configurations match (at least cache line sizes etc).
|
||||||
|
|
||||||
|
""patch-dtb" searches for ASCII "OWRTDTB:" strign and copies external
|
||||||
|
.dtb right after it, keeping the string in place.
|
||||||
|
|
||||||
|
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||||
|
---
|
||||||
|
arch/arc/kernel/head.S | 10 ++++++++++
|
||||||
|
arch/arc/kernel/setup.c | 4 +++-
|
||||||
|
arch/arc/kernel/vmlinux.lds.S | 13 +++++++++++++
|
||||||
|
3 files changed, 26 insertions(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/arch/arc/kernel/head.S
|
||||||
|
+++ b/arch/arc/kernel/head.S
|
||||||
|
@@ -49,6 +49,16 @@
|
||||||
|
1:
|
||||||
|
.endm
|
||||||
|
|
||||||
|
+; Here "patch-dtb" will embed external .dtb
|
||||||
|
+; Note "patch-dtb" searches for ASCII "OWRTDTB:" string
|
||||||
|
+; and pastes .dtb right after it, hense the string precedes
|
||||||
|
+; __image_dtb symbol.
|
||||||
|
+ .section .owrt, "aw",@progbits
|
||||||
|
+ .ascii "OWRTDTB:"
|
||||||
|
+ENTRY(__image_dtb)
|
||||||
|
+ .fill 0x4000
|
||||||
|
+END(__image_dtb)
|
||||||
|
+
|
||||||
|
.section .init.text, "ax",@progbits
|
||||||
|
|
||||||
|
;----------------------------------------------------------------
|
||||||
|
--- a/arch/arc/kernel/setup.c
|
||||||
|
+++ b/arch/arc/kernel/setup.c
|
||||||
|
@@ -388,6 +388,8 @@ static inline int is_kernel(unsigned lon
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
+extern struct boot_param_header __image_dtb;
|
||||||
|
+
|
||||||
|
void __init setup_arch(char **cmdline_p)
|
||||||
|
{
|
||||||
|
#ifdef CONFIG_ARC_UBOOT_SUPPORT
|
||||||
|
@@ -401,7 +403,7 @@ void __init setup_arch(char **cmdline_p)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
/* No, so try the embedded one */
|
||||||
|
- machine_desc = setup_machine_fdt(__dtb_start);
|
||||||
|
+ machine_desc = setup_machine_fdt(&__image_dtb);
|
||||||
|
if (!machine_desc)
|
||||||
|
panic("Embedded DT invalid\n");
|
||||||
|
|
||||||
|
--- a/arch/arc/kernel/vmlinux.lds.S
|
||||||
|
+++ b/arch/arc/kernel/vmlinux.lds.S
|
||||||
|
@@ -30,6 +30,19 @@ SECTIONS
|
||||||
|
|
||||||
|
. = CONFIG_LINUX_LINK_BASE;
|
||||||
|
|
||||||
|
+ /*
|
||||||
|
+ * In OpenWRT we want to patch built binary embedding .dtb of choice.
|
||||||
|
+ * This is implemented with "patch-dtb" utility which searches for
|
||||||
|
+ * "OWRTDTB:" string in first 16k of image and if it is found
|
||||||
|
+ * copies .dtb right after mentioned string.
|
||||||
|
+ *
|
||||||
|
+ * Note: "OWRTDTB:" won't be overwritten with .dtb, .dtb will follow it.
|
||||||
|
+ */
|
||||||
|
+ .owrt : {
|
||||||
|
+ *(.owrt)
|
||||||
|
+ . = ALIGN(PAGE_SIZE);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
_int_vec_base_lds = .;
|
||||||
|
.vector : {
|
||||||
|
*(.vector)
|
|
@ -0,0 +1,26 @@
|
||||||
|
From af737b55fc7c61f17da9ae89fba536e0a9338e98 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Alexey Brodkin <abrodkin@synopsys.com>
|
||||||
|
Date: Mon, 14 Mar 2016 17:26:34 +0300
|
||||||
|
Subject: [PATCH] arc: enable unaligned access in kernel mode
|
||||||
|
|
||||||
|
This enables misaligned access handling even in kernel mode.
|
||||||
|
Some wireless drivers (ath9k-htc and mt7601u) use misaligned accesses
|
||||||
|
here and there and to cope with that without fixing stuff in the drivers
|
||||||
|
we're just gracefully handling it on ARC.
|
||||||
|
|
||||||
|
Signed-off-by: Alexey Brodkin <abrodkin@synopsys.com>
|
||||||
|
---
|
||||||
|
arch/arc/kernel/unaligned.c | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
--- a/arch/arc/kernel/unaligned.c
|
||||||
|
+++ b/arch/arc/kernel/unaligned.c
|
||||||
|
@@ -206,7 +206,7 @@ int misaligned_fixup(unsigned long addre
|
||||||
|
char buf[TASK_COMM_LEN];
|
||||||
|
|
||||||
|
/* handle user mode only and only if enabled by sysadmin */
|
||||||
|
- if (!user_mode(regs) || !unaligned_enabled)
|
||||||
|
+ if (!unaligned_enabled)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
if (no_unaligned_warning) {
|
|
@ -0,0 +1,112 @@
|
||||||
|
--- a/drivers/mtd/Kconfig
|
||||||
|
+++ b/drivers/mtd/Kconfig
|
||||||
|
@@ -12,6 +12,23 @@ menuconfig MTD
|
||||||
|
|
||||||
|
if MTD
|
||||||
|
|
||||||
|
+menu "OpenWrt specific MTD options"
|
||||||
|
+
|
||||||
|
+config MTD_ROOTFS_ROOT_DEV
|
||||||
|
+ bool "Automatically set 'rootfs' partition to be root filesystem"
|
||||||
|
+ default y
|
||||||
|
+
|
||||||
|
+config MTD_SPLIT_FIRMWARE
|
||||||
|
+ bool "Automatically split firmware partition for kernel+rootfs"
|
||||||
|
+ default y
|
||||||
|
+
|
||||||
|
+config MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
+ string "Firmware partition name"
|
||||||
|
+ depends on MTD_SPLIT_FIRMWARE
|
||||||
|
+ default "firmware"
|
||||||
|
+
|
||||||
|
+endmenu
|
||||||
|
+
|
||||||
|
config MTD_TESTS
|
||||||
|
tristate "MTD tests support (DANGEROUS)"
|
||||||
|
depends on m
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -29,10 +29,12 @@
|
||||||
|
#include <linux/kmod.h>
|
||||||
|
#include <linux/mtd/mtd.h>
|
||||||
|
#include <linux/mtd/partitions.h>
|
||||||
|
+#include <linux/magic.h>
|
||||||
|
#include <linux/of.h>
|
||||||
|
#include <linux/err.h>
|
||||||
|
|
||||||
|
#include "mtdcore.h"
|
||||||
|
+#include "mtdsplit/mtdsplit.h"
|
||||||
|
|
||||||
|
/* Our partition linked list */
|
||||||
|
static LIST_HEAD(mtd_partitions);
|
||||||
|
@@ -46,6 +48,8 @@ struct mtd_part {
|
||||||
|
struct list_head list;
|
||||||
|
};
|
||||||
|
|
||||||
|
+static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part);
|
||||||
|
+
|
||||||
|
/*
|
||||||
|
* Given a pointer to the MTD object in the mtd_part structure, we can retrieve
|
||||||
|
* the pointer to that structure.
|
||||||
|
@@ -650,6 +654,7 @@ int mtd_add_partition(struct mtd_info *m
|
||||||
|
mutex_unlock(&mtd_partitions_mutex);
|
||||||
|
|
||||||
|
add_mtd_device(&new->mtd);
|
||||||
|
+ mtd_partition_split(master, new);
|
||||||
|
|
||||||
|
mtd_add_partition_attrs(new);
|
||||||
|
|
||||||
|
@@ -682,6 +687,35 @@ int mtd_del_partition(struct mtd_info *m
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_del_partition);
|
||||||
|
|
||||||
|
+#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
+#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
+#else
|
||||||
|
+#define SPLIT_FIRMWARE_NAME "unused"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
+static void split_firmware(struct mtd_info *master, struct mtd_part *part)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
|
||||||
|
+ int offset, int size)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static void mtd_partition_split(struct mtd_info *master, struct mtd_part *part)
|
||||||
|
+{
|
||||||
|
+ static int rootfs_found = 0;
|
||||||
|
+
|
||||||
|
+ if (rootfs_found)
|
||||||
|
+ return;
|
||||||
|
+
|
||||||
|
+ if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||||
|
+ IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||||
|
+ split_firmware(master, part);
|
||||||
|
+
|
||||||
|
+ arch_split_mtd_part(master, part->mtd.name, part->offset,
|
||||||
|
+ part->mtd.size);
|
||||||
|
+}
|
||||||
|
/*
|
||||||
|
* This function, given a master MTD object and a partition table, creates
|
||||||
|
* and registers slave MTD objects which are bound to the master according to
|
||||||
|
@@ -713,6 +747,7 @@ int add_mtd_partitions(struct mtd_info *
|
||||||
|
mutex_unlock(&mtd_partitions_mutex);
|
||||||
|
|
||||||
|
add_mtd_device(&slave->mtd);
|
||||||
|
+ mtd_partition_split(master, slave);
|
||||||
|
mtd_add_partition_attrs(slave);
|
||||||
|
|
||||||
|
cur_offset = slave->offset + slave->mtd.size;
|
||||||
|
--- a/include/linux/mtd/partitions.h
|
||||||
|
+++ b/include/linux/mtd/partitions.h
|
||||||
|
@@ -101,5 +101,7 @@ int mtd_add_partition(struct mtd_info *m
|
||||||
|
long long offset, long long length);
|
||||||
|
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||||
|
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||||
|
+extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||||
|
+ const char *name, int offset, int size);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,112 @@
|
||||||
|
From 02cff0ccaa6d364f5c1eeea83f47ac80ccc967d4 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
Date: Tue, 3 Sep 2013 18:11:50 +0200
|
||||||
|
Subject: [PATCH] mtd: add support for different partition parser types
|
||||||
|
|
||||||
|
Signed-off-by: Gabor Juhos <juhosg@openwrt.org>
|
||||||
|
---
|
||||||
|
drivers/mtd/mtdpart.c | 56 ++++++++++++++++++++++++++++++++++++++++
|
||||||
|
include/linux/mtd/partitions.h | 11 ++++++++
|
||||||
|
2 files changed, 67 insertions(+)
|
||||||
|
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -945,6 +945,62 @@ void mtd_part_parser_cleanup(struct mtd_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+static struct mtd_part_parser *
|
||||||
|
+get_partition_parser_by_type(enum mtd_parser_type type,
|
||||||
|
+ struct mtd_part_parser *start)
|
||||||
|
+{
|
||||||
|
+ struct mtd_part_parser *p, *ret = NULL;
|
||||||
|
+
|
||||||
|
+ spin_lock(&part_parser_lock);
|
||||||
|
+
|
||||||
|
+ p = list_prepare_entry(start, &part_parsers, list);
|
||||||
|
+ if (start)
|
||||||
|
+ mtd_part_parser_put(start);
|
||||||
|
+
|
||||||
|
+ list_for_each_entry_continue(p, &part_parsers, list) {
|
||||||
|
+ if (p->type == type && try_module_get(p->owner)) {
|
||||||
|
+ ret = p;
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ spin_unlock(&part_parser_lock);
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+int parse_mtd_partitions_by_type(struct mtd_info *master,
|
||||||
|
+ enum mtd_parser_type type,
|
||||||
|
+ const struct mtd_partition **pparts,
|
||||||
|
+ struct mtd_part_parser_data *data)
|
||||||
|
+{
|
||||||
|
+ struct mtd_part_parser *prev = NULL;
|
||||||
|
+ int ret = 0;
|
||||||
|
+
|
||||||
|
+ while (1) {
|
||||||
|
+ struct mtd_part_parser *parser;
|
||||||
|
+
|
||||||
|
+ parser = get_partition_parser_by_type(type, prev);
|
||||||
|
+ if (!parser)
|
||||||
|
+ break;
|
||||||
|
+
|
||||||
|
+ ret = (*parser->parse_fn)(master, pparts, data);
|
||||||
|
+
|
||||||
|
+ if (ret > 0) {
|
||||||
|
+ mtd_part_parser_put(parser);
|
||||||
|
+ printk(KERN_NOTICE
|
||||||
|
+ "%d %s partitions found on MTD device %s\n",
|
||||||
|
+ ret, parser->name, master->name);
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ prev = parser;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return ret;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(parse_mtd_partitions_by_type);
|
||||||
|
+
|
||||||
|
int mtd_is_partition(const struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
struct mtd_part *part;
|
||||||
|
--- a/include/linux/mtd/partitions.h
|
||||||
|
+++ b/include/linux/mtd/partitions.h
|
||||||
|
@@ -60,11 +60,14 @@ struct mtd_part_parser_data {
|
||||||
|
unsigned long origin;
|
||||||
|
};
|
||||||
|
|
||||||
|
-
|
||||||
|
/*
|
||||||
|
* Functions dealing with the various ways of partitioning the space
|
||||||
|
*/
|
||||||
|
|
||||||
|
+enum mtd_parser_type {
|
||||||
|
+ MTD_PARSER_TYPE_DEVICE = 0,
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
struct mtd_part_parser {
|
||||||
|
struct list_head list;
|
||||||
|
struct module *owner;
|
||||||
|
@@ -72,6 +75,7 @@ struct mtd_part_parser {
|
||||||
|
int (*parse_fn)(struct mtd_info *, const struct mtd_partition **,
|
||||||
|
struct mtd_part_parser_data *);
|
||||||
|
void (*cleanup)(const struct mtd_partition *pparts, int nr_parts);
|
||||||
|
+ enum mtd_parser_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Container for passing around a set of parsed partitions */
|
||||||
|
@@ -104,4 +108,9 @@ uint64_t mtd_get_device_size(const struc
|
||||||
|
extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||||
|
const char *name, int offset, int size);
|
||||||
|
|
||||||
|
+int parse_mtd_partitions_by_type(struct mtd_info *master,
|
||||||
|
+ enum mtd_parser_type type,
|
||||||
|
+ const struct mtd_partition **pparts,
|
||||||
|
+ struct mtd_part_parser_data *data);
|
||||||
|
+
|
||||||
|
#endif
|
|
@ -0,0 +1,71 @@
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -687,6 +687,36 @@ int mtd_del_partition(struct mtd_info *m
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_del_partition);
|
||||||
|
|
||||||
|
+static int
|
||||||
|
+run_parsers_by_type(struct mtd_part *slave, enum mtd_parser_type type)
|
||||||
|
+{
|
||||||
|
+ struct mtd_partition *parts;
|
||||||
|
+ int nr_parts;
|
||||||
|
+ int i;
|
||||||
|
+
|
||||||
|
+ nr_parts = parse_mtd_partitions_by_type(&slave->mtd, type, (const struct mtd_partition **)&parts,
|
||||||
|
+ NULL);
|
||||||
|
+ if (nr_parts <= 0)
|
||||||
|
+ return nr_parts;
|
||||||
|
+
|
||||||
|
+ if (WARN_ON(!parts))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ for (i = 0; i < nr_parts; i++) {
|
||||||
|
+ /* adjust partition offsets */
|
||||||
|
+ parts[i].offset += slave->offset;
|
||||||
|
+
|
||||||
|
+ mtd_add_partition(slave->master,
|
||||||
|
+ parts[i].name,
|
||||||
|
+ parts[i].offset,
|
||||||
|
+ parts[i].size);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ kfree(parts);
|
||||||
|
+
|
||||||
|
+ return nr_parts;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
#else
|
||||||
|
@@ -695,6 +725,7 @@ EXPORT_SYMBOL_GPL(mtd_del_partition);
|
||||||
|
|
||||||
|
static void split_firmware(struct mtd_info *master, struct mtd_part *part)
|
||||||
|
{
|
||||||
|
+ run_parsers_by_type(part, MTD_PARSER_TYPE_FIRMWARE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void __weak arch_split_mtd_part(struct mtd_info *master, const char *name,
|
||||||
|
@@ -709,6 +740,12 @@ static void mtd_partition_split(struct m
|
||||||
|
if (rootfs_found)
|
||||||
|
return;
|
||||||
|
|
||||||
|
+ if (!strcmp(part->mtd.name, "rootfs")) {
|
||||||
|
+ run_parsers_by_type(part, MTD_PARSER_TYPE_ROOTFS);
|
||||||
|
+
|
||||||
|
+ rootfs_found = 1;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
if (!strcmp(part->mtd.name, SPLIT_FIRMWARE_NAME) &&
|
||||||
|
IS_ENABLED(CONFIG_MTD_SPLIT_FIRMWARE))
|
||||||
|
split_firmware(master, part);
|
||||||
|
--- a/include/linux/mtd/partitions.h
|
||||||
|
+++ b/include/linux/mtd/partitions.h
|
||||||
|
@@ -66,6 +66,8 @@ struct mtd_part_parser_data {
|
||||||
|
|
||||||
|
enum mtd_parser_type {
|
||||||
|
MTD_PARSER_TYPE_DEVICE = 0,
|
||||||
|
+ MTD_PARSER_TYPE_ROOTFS,
|
||||||
|
+ MTD_PARSER_TYPE_FIRMWARE,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mtd_part_parser {
|
|
@ -0,0 +1,22 @@
|
||||||
|
--- a/drivers/mtd/Kconfig
|
||||||
|
+++ b/drivers/mtd/Kconfig
|
||||||
|
@@ -27,6 +27,8 @@ config MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
depends on MTD_SPLIT_FIRMWARE
|
||||||
|
default "firmware"
|
||||||
|
|
||||||
|
+source "drivers/mtd/mtdsplit/Kconfig"
|
||||||
|
+
|
||||||
|
endmenu
|
||||||
|
|
||||||
|
config MTD_TESTS
|
||||||
|
--- a/drivers/mtd/Makefile
|
||||||
|
+++ b/drivers/mtd/Makefile
|
||||||
|
@@ -6,6 +6,8 @@
|
||||||
|
obj-$(CONFIG_MTD) += mtd.o
|
||||||
|
mtd-y := mtdcore.o mtdsuper.o mtdconcat.o mtdpart.o mtdchar.o
|
||||||
|
|
||||||
|
+obj-$(CONFIG_MTD_SPLIT) += mtdsplit/
|
||||||
|
+
|
||||||
|
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
|
||||||
|
obj-$(CONFIG_MTD_REDBOOT_PARTS) += redboot.o
|
||||||
|
obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdlinepart.o
|
|
@ -0,0 +1,101 @@
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -493,14 +493,12 @@ static struct mtd_part *allocate_partiti
|
||||||
|
if (slave->offset == MTDPART_OFS_APPEND)
|
||||||
|
slave->offset = cur_offset;
|
||||||
|
if (slave->offset == MTDPART_OFS_NXTBLK) {
|
||||||
|
- slave->offset = cur_offset;
|
||||||
|
- if (mtd_mod_by_eb(cur_offset, master) != 0) {
|
||||||
|
- /* Round up to next erasesize */
|
||||||
|
- slave->offset = (mtd_div_by_eb(cur_offset, master) + 1) * master->erasesize;
|
||||||
|
+ /* Round up to next erasesize */
|
||||||
|
+ slave->offset = mtd_roundup_to_eb(cur_offset, master);
|
||||||
|
+ if (slave->offset != cur_offset)
|
||||||
|
printk(KERN_NOTICE "Moving partition %d: "
|
||||||
|
"0x%012llx -> 0x%012llx\n", partno,
|
||||||
|
(unsigned long long)cur_offset, (unsigned long long)slave->offset);
|
||||||
|
- }
|
||||||
|
}
|
||||||
|
if (slave->offset == MTDPART_OFS_RETAIN) {
|
||||||
|
slave->offset = cur_offset;
|
||||||
|
@@ -717,6 +715,17 @@ run_parsers_by_type(struct mtd_part *sla
|
||||||
|
return nr_parts;
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline unsigned long
|
||||||
|
+mtd_pad_erasesize(struct mtd_info *mtd, int offset, int len)
|
||||||
|
+{
|
||||||
|
+ unsigned long mask = mtd->erasesize - 1;
|
||||||
|
+
|
||||||
|
+ len += offset & mask;
|
||||||
|
+ len = (len + mask) & ~mask;
|
||||||
|
+ len -= offset & mask;
|
||||||
|
+ return len;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
#ifdef CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
#define SPLIT_FIRMWARE_NAME CONFIG_MTD_SPLIT_FIRMWARE_NAME
|
||||||
|
#else
|
||||||
|
@@ -1055,6 +1064,24 @@ int mtd_is_partition(const struct mtd_in
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(mtd_is_partition);
|
||||||
|
|
||||||
|
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd)
|
||||||
|
+{
|
||||||
|
+ if (!mtd_is_partition(mtd))
|
||||||
|
+ return (struct mtd_info *)mtd;
|
||||||
|
+
|
||||||
|
+ return mtd_to_part(mtd)->master;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(mtdpart_get_master);
|
||||||
|
+
|
||||||
|
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd)
|
||||||
|
+{
|
||||||
|
+ if (!mtd_is_partition(mtd))
|
||||||
|
+ return 0;
|
||||||
|
+
|
||||||
|
+ return mtd_to_part(mtd)->offset;
|
||||||
|
+}
|
||||||
|
+EXPORT_SYMBOL_GPL(mtdpart_get_offset);
|
||||||
|
+
|
||||||
|
/* Returns the size of the entire flash chip */
|
||||||
|
uint64_t mtd_get_device_size(const struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
--- a/include/linux/mtd/partitions.h
|
||||||
|
+++ b/include/linux/mtd/partitions.h
|
||||||
|
@@ -106,6 +106,8 @@ int mtd_is_partition(const struct mtd_in
|
||||||
|
int mtd_add_partition(struct mtd_info *master, const char *name,
|
||||||
|
long long offset, long long length);
|
||||||
|
int mtd_del_partition(struct mtd_info *master, int partno);
|
||||||
|
+struct mtd_info *mtdpart_get_master(const struct mtd_info *mtd);
|
||||||
|
+uint64_t mtdpart_get_offset(const struct mtd_info *mtd);
|
||||||
|
uint64_t mtd_get_device_size(const struct mtd_info *mtd);
|
||||||
|
extern void __weak arch_split_mtd_part(struct mtd_info *master,
|
||||||
|
const char *name, int offset, int size);
|
||||||
|
--- a/include/linux/mtd/mtd.h
|
||||||
|
+++ b/include/linux/mtd/mtd.h
|
||||||
|
@@ -472,6 +472,24 @@ static inline uint32_t mtd_mod_by_eb(uin
|
||||||
|
return do_div(sz, mtd->erasesize);
|
||||||
|
}
|
||||||
|
|
||||||
|
+static inline uint64_t mtd_roundup_to_eb(uint64_t sz, struct mtd_info *mtd)
|
||||||
|
+{
|
||||||
|
+ if (mtd_mod_by_eb(sz, mtd) == 0)
|
||||||
|
+ return sz;
|
||||||
|
+
|
||||||
|
+ /* Round up to next erase block */
|
||||||
|
+ return (mtd_div_by_eb(sz, mtd) + 1) * mtd->erasesize;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+static inline uint64_t mtd_rounddown_to_eb(uint64_t sz, struct mtd_info *mtd)
|
||||||
|
+{
|
||||||
|
+ if (mtd_mod_by_eb(sz, mtd) == 0)
|
||||||
|
+ return sz;
|
||||||
|
+
|
||||||
|
+ /* Round down to the start of the current erase block */
|
||||||
|
+ return (mtd_div_by_eb(sz, mtd)) * mtd->erasesize;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline uint32_t mtd_div_by_ws(uint64_t sz, struct mtd_info *mtd)
|
||||||
|
{
|
||||||
|
if (mtd->writesize_shift)
|
|
@ -0,0 +1,18 @@
|
||||||
|
--- a/include/linux/mtd/partitions.h
|
||||||
|
+++ b/include/linux/mtd/partitions.h
|
||||||
|
@@ -35,6 +35,7 @@
|
||||||
|
* Note: writeable partitions require their size and offset be
|
||||||
|
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
|
||||||
|
*/
|
||||||
|
+struct mtd_info;
|
||||||
|
|
||||||
|
struct mtd_partition {
|
||||||
|
const char *name; /* identifier string */
|
||||||
|
@@ -49,7 +50,6 @@ struct mtd_partition {
|
||||||
|
#define MTDPART_SIZ_FULL (0)
|
||||||
|
|
||||||
|
|
||||||
|
-struct mtd_info;
|
||||||
|
struct device_node;
|
||||||
|
|
||||||
|
/**
|
|
@ -0,0 +1,142 @@
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -36,6 +36,8 @@
|
||||||
|
#include "mtdcore.h"
|
||||||
|
#include "mtdsplit/mtdsplit.h"
|
||||||
|
|
||||||
|
+#define MTD_ERASE_PARTIAL 0x8000 /* partition only covers parts of an erase block */
|
||||||
|
+
|
||||||
|
/* Our partition linked list */
|
||||||
|
static LIST_HEAD(mtd_partitions);
|
||||||
|
static DEFINE_MUTEX(mtd_partitions_mutex);
|
||||||
|
@@ -235,13 +237,61 @@ static int part_erase(struct mtd_info *m
|
||||||
|
struct mtd_part *part = mtd_to_part(mtd);
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
+
|
||||||
|
+ instr->partial_start = false;
|
||||||
|
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
|
||||||
|
+ size_t readlen = 0;
|
||||||
|
+ u64 mtd_ofs;
|
||||||
|
+
|
||||||
|
+ instr->erase_buf = kmalloc(part->master->erasesize, GFP_ATOMIC);
|
||||||
|
+ if (!instr->erase_buf)
|
||||||
|
+ return -ENOMEM;
|
||||||
|
+
|
||||||
|
+ mtd_ofs = part->offset + instr->addr;
|
||||||
|
+ instr->erase_buf_ofs = do_div(mtd_ofs, part->master->erasesize);
|
||||||
|
+
|
||||||
|
+ if (instr->erase_buf_ofs > 0) {
|
||||||
|
+ instr->addr -= instr->erase_buf_ofs;
|
||||||
|
+ ret = mtd_read(part->master,
|
||||||
|
+ instr->addr + part->offset,
|
||||||
|
+ part->master->erasesize,
|
||||||
|
+ &readlen, instr->erase_buf);
|
||||||
|
+
|
||||||
|
+ instr->len += instr->erase_buf_ofs;
|
||||||
|
+ instr->partial_start = true;
|
||||||
|
+ } else {
|
||||||
|
+ mtd_ofs = part->offset + part->mtd.size;
|
||||||
|
+ instr->erase_buf_ofs = part->master->erasesize -
|
||||||
|
+ do_div(mtd_ofs, part->master->erasesize);
|
||||||
|
+
|
||||||
|
+ if (instr->erase_buf_ofs > 0) {
|
||||||
|
+ instr->len += instr->erase_buf_ofs;
|
||||||
|
+ ret = mtd_read(part->master,
|
||||||
|
+ part->offset + instr->addr +
|
||||||
|
+ instr->len - part->master->erasesize,
|
||||||
|
+ part->master->erasesize, &readlen,
|
||||||
|
+ instr->erase_buf);
|
||||||
|
+ } else {
|
||||||
|
+ ret = 0;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ if (ret < 0) {
|
||||||
|
+ kfree(instr->erase_buf);
|
||||||
|
+ return ret;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
instr->addr += part->offset;
|
||||||
|
ret = part->master->_erase(part->master, instr);
|
||||||
|
if (ret) {
|
||||||
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
|
instr->fail_addr -= part->offset;
|
||||||
|
instr->addr -= part->offset;
|
||||||
|
+ if (mtd->flags & MTD_ERASE_PARTIAL)
|
||||||
|
+ kfree(instr->erase_buf);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -249,6 +299,25 @@ void mtd_erase_callback(struct erase_inf
|
||||||
|
{
|
||||||
|
if (instr->mtd->_erase == part_erase) {
|
||||||
|
struct mtd_part *part = mtd_to_part(instr->mtd);
|
||||||
|
+ size_t wrlen = 0;
|
||||||
|
+
|
||||||
|
+ if (instr->mtd->flags & MTD_ERASE_PARTIAL) {
|
||||||
|
+ if (instr->partial_start) {
|
||||||
|
+ part->master->_write(part->master,
|
||||||
|
+ instr->addr, instr->erase_buf_ofs,
|
||||||
|
+ &wrlen, instr->erase_buf);
|
||||||
|
+ instr->addr += instr->erase_buf_ofs;
|
||||||
|
+ } else {
|
||||||
|
+ instr->len -= instr->erase_buf_ofs;
|
||||||
|
+ part->master->_write(part->master,
|
||||||
|
+ instr->addr + instr->len,
|
||||||
|
+ instr->erase_buf_ofs, &wrlen,
|
||||||
|
+ instr->erase_buf +
|
||||||
|
+ part->master->erasesize -
|
||||||
|
+ instr->erase_buf_ofs);
|
||||||
|
+ }
|
||||||
|
+ kfree(instr->erase_buf);
|
||||||
|
+ }
|
||||||
|
|
||||||
|
if (instr->fail_addr != MTD_FAIL_ADDR_UNKNOWN)
|
||||||
|
instr->fail_addr -= part->offset;
|
||||||
|
@@ -562,17 +631,20 @@ static struct mtd_part *allocate_partiti
|
||||||
|
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||||
|
mtd_mod_by_eb(slave->offset, &slave->mtd)) {
|
||||||
|
/* Doesn't start on a boundary of major erase size */
|
||||||
|
- /* FIXME: Let it be writable if it is on a boundary of
|
||||||
|
- * _minor_ erase size though */
|
||||||
|
- slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||||
|
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't start on an erase block boundary -- force read-only\n",
|
||||||
|
- part->name);
|
||||||
|
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||||
|
+ if (((u32) slave->mtd.size) > master->erasesize)
|
||||||
|
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||||
|
+ else
|
||||||
|
+ slave->mtd.erasesize = slave->mtd.size;
|
||||||
|
}
|
||||||
|
if ((slave->mtd.flags & MTD_WRITEABLE) &&
|
||||||
|
- mtd_mod_by_eb(slave->mtd.size, &slave->mtd)) {
|
||||||
|
- slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||||
|
- printk(KERN_WARNING"mtd: partition \"%s\" doesn't end on an erase block -- force read-only\n",
|
||||||
|
- part->name);
|
||||||
|
+ mtd_mod_by_eb(slave->offset + slave->mtd.size, &slave->mtd)) {
|
||||||
|
+ slave->mtd.flags |= MTD_ERASE_PARTIAL;
|
||||||
|
+
|
||||||
|
+ if ((u32) slave->mtd.size > master->erasesize)
|
||||||
|
+ slave->mtd.flags &= ~MTD_WRITEABLE;
|
||||||
|
+ else
|
||||||
|
+ slave->mtd.erasesize = slave->mtd.size;
|
||||||
|
}
|
||||||
|
|
||||||
|
mtd_set_ooblayout(&slave->mtd, &part_ooblayout_ops);
|
||||||
|
--- a/include/linux/mtd/mtd.h
|
||||||
|
+++ b/include/linux/mtd/mtd.h
|
||||||
|
@@ -55,6 +55,10 @@ struct erase_info {
|
||||||
|
u_long priv;
|
||||||
|
u_char state;
|
||||||
|
struct erase_info *next;
|
||||||
|
+
|
||||||
|
+ u8 *erase_buf;
|
||||||
|
+ u32 erase_buf_ofs;
|
||||||
|
+ bool partial_start;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct mtd_erase_region_info {
|
|
@ -0,0 +1,20 @@
|
||||||
|
--- a/drivers/mtd/mtdpart.c
|
||||||
|
+++ b/drivers/mtd/mtdpart.c
|
||||||
|
@@ -337,7 +337,16 @@ static int part_lock(struct mtd_info *mt
|
||||||
|
static int part_unlock(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
||||||
|
{
|
||||||
|
struct mtd_part *part = mtd_to_part(mtd);
|
||||||
|
- return part->master->_unlock(part->master, ofs + part->offset, len);
|
||||||
|
+
|
||||||
|
+ ofs += part->offset;
|
||||||
|
+
|
||||||
|
+ if (mtd->flags & MTD_ERASE_PARTIAL) {
|
||||||
|
+ /* round up len to next erasesize and round down offset to prev block */
|
||||||
|
+ len = (mtd_div_by_eb(len, part->master) + 1) * part->master->erasesize;
|
||||||
|
+ ofs &= ~(part->master->erasesize - 1);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return part->master->_unlock(part->master, ofs, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int part_is_locked(struct mtd_info *mtd, loff_t ofs, uint64_t len)
|
|
@ -0,0 +1,30 @@
|
||||||
|
--- a/drivers/mtd/redboot.c
|
||||||
|
+++ b/drivers/mtd/redboot.c
|
||||||
|
@@ -265,14 +265,21 @@ static int parse_redboot_partitions(stru
|
||||||
|
#endif
|
||||||
|
names += strlen(names)+1;
|
||||||
|
|
||||||
|
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||||
|
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
|
||||||
|
- i++;
|
||||||
|
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||||
|
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||||
|
- parts[i].name = nullname;
|
||||||
|
- }
|
||||||
|
+ if (!strcmp(parts[i].name, "rootfs")) {
|
||||||
|
+ parts[i].size = fl->next->img->flash_base;
|
||||||
|
+ parts[i].size &= ~(master->erasesize - 1);
|
||||||
|
+ parts[i].size -= parts[i].offset;
|
||||||
|
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
|
||||||
|
+ nrparts--;
|
||||||
|
+ } else {
|
||||||
|
+ i++;
|
||||||
|
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
|
||||||
|
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
|
||||||
|
+ parts[i].name = nullname;
|
||||||
|
#endif
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
tmp_fl = fl;
|
||||||
|
fl = fl->next;
|
||||||
|
kfree(tmp_fl);
|
|
@ -0,0 +1,35 @@
|
||||||
|
--- a/drivers/mtd/Kconfig
|
||||||
|
+++ b/drivers/mtd/Kconfig
|
||||||
|
@@ -174,6 +174,22 @@ config MTD_BCM47XX_PARTS
|
||||||
|
This provides partitions parser for devices based on BCM47xx
|
||||||
|
boards.
|
||||||
|
|
||||||
|
+config MTD_MYLOADER_PARTS
|
||||||
|
+ tristate "MyLoader partition parsing"
|
||||||
|
+ depends on ADM5120 || ATH25 || ATH79
|
||||||
|
+ ---help---
|
||||||
|
+ MyLoader is a bootloader which allows the user to define partitions
|
||||||
|
+ in flash devices, by putting a table in the second erase block
|
||||||
|
+ on the device, similar to a partition table. This table gives the
|
||||||
|
+ offsets and lengths of the user defined partitions.
|
||||||
|
+
|
||||||
|
+ If you need code which can detect and parse these tables, and
|
||||||
|
+ register MTD 'partitions' corresponding to each image detected,
|
||||||
|
+ enable this option.
|
||||||
|
+
|
||||||
|
+ You will still need the parsing functions to be called by the driver
|
||||||
|
+ for your particular device. It won't happen automatically.
|
||||||
|
+
|
||||||
|
comment "User Modules And Translation Layers"
|
||||||
|
|
||||||
|
#
|
||||||
|
--- a/drivers/mtd/Makefile
|
||||||
|
+++ b/drivers/mtd/Makefile
|
||||||
|
@@ -15,6 +15,7 @@ obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
|
||||||
|
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
|
||||||
|
obj-$(CONFIG_MTD_BCM63XX_PARTS) += bcm63xxpart.o
|
||||||
|
obj-$(CONFIG_MTD_BCM47XX_PARTS) += bcm47xxpart.o
|
||||||
|
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
|
||||||
|
|
||||||
|
# 'Users' - code which presents functionality to userspace.
|
||||||
|
obj-$(CONFIG_MTD_BLKDEVS) += mtd_blkdevs.o
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue