--- /dev/null
+From f9e1e7e59d60d85684a05366d282b6d6bdfdb687 Mon Sep 17 00:00:00 2001
+From: "Peter Pan(潘卫平)" <panweiping3@gmail.com>
+Date: Thu, 1 Dec 2011 15:47:06 +0000
+Subject: ipv4: flush route cache after change accept_local
+
+
+From: Weiping Pan <panweiping3@gmail.com>
+
+[ Upstream commit d01ff0a049f749e0bf10a35bb23edd012718c8c2 ]
+
+After reset ipv4_devconf->data[IPV4_DEVCONF_ACCEPT_LOCAL] to 0,
+we should flush route cache, or it will continue receive packets with local
+source address, which should be dropped.
+
+Signed-off-by: Weiping Pan <panweiping3@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/ipv4/devinet.c | 5 +++++
+ 1 file changed, 5 insertions(+)
+
+--- a/net/ipv4/devinet.c
++++ b/net/ipv4/devinet.c
+@@ -1490,7 +1490,9 @@ static int devinet_conf_proc(ctl_table *
+ void __user *buffer,
+ size_t *lenp, loff_t *ppos)
+ {
++ int old_value = *(int *)ctl->data;
+ int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
++ int new_value = *(int *)ctl->data;
+
+ if (write) {
+ struct ipv4_devconf *cnf = ctl->extra1;
+@@ -1501,6 +1503,9 @@ static int devinet_conf_proc(ctl_table *
+
+ if (cnf == net->ipv4.devconf_dflt)
+ devinet_copy_dflt_conf(net, i);
++ if (i == IPV4_DEVCONF_ACCEPT_LOCAL - 1)
++ if ((new_value == 0) && (old_value != 0))
++ rt_cache_flush(net, 0);
+ }
+
+ return ret;
--- /dev/null
+From 92023c1e1af8d82e1dce92a17efd0f1adffa2dd2 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Wed, 21 Dec 2011 15:47:16 -0500
+Subject: ipv4: reintroduce route cache garbage collector
+
+
+From: Eric Dumazet <eric.dumazet@gmail.com>
+
+[ Upstream commit 9f28a2fc0bd77511f649c0a788c7bf9a5fd04edb ]
+
+Commit 2c8cec5c10b (ipv4: Cache learned PMTU information in inetpeer)
+removed IP route cache garbage collector a bit too soon, as this gc was
+responsible for expired routes cleanup, releasing their neighbour
+reference.
+
+As pointed out by Robert Gladewitz, recent kernels can fill and exhaust
+their neighbour cache.
+
+Reintroduce the garbage collection, since we'll have to wait our
+neighbour lookups become refcount-less to not depend on this stuff.
+
+Reported-by: Robert Gladewitz <gladewitz@gmx.de>
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/ipv4/route.c | 106 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 106 insertions(+)
+
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -134,6 +134,9 @@ static int ip_rt_min_advmss __read_mostl
+ static int rt_chain_length_max __read_mostly = 20;
+ static int redirect_genid;
+
++static struct delayed_work expires_work;
++static unsigned long expires_ljiffies;
++
+ /*
+ * Interface to generic destination cache.
+ */
+@@ -831,6 +834,97 @@ static int has_noalias(const struct rtab
+ return ONE;
+ }
+
++static void rt_check_expire(void)
++{
++ static unsigned int rover;
++ unsigned int i = rover, goal;
++ struct rtable *rth;
++ struct rtable __rcu **rthp;
++ unsigned long samples = 0;
++ unsigned long sum = 0, sum2 = 0;
++ unsigned long delta;
++ u64 mult;
++
++ delta = jiffies - expires_ljiffies;
++ expires_ljiffies = jiffies;
++ mult = ((u64)delta) << rt_hash_log;
++ if (ip_rt_gc_timeout > 1)
++ do_div(mult, ip_rt_gc_timeout);
++ goal = (unsigned int)mult;
++ if (goal > rt_hash_mask)
++ goal = rt_hash_mask + 1;
++ for (; goal > 0; goal--) {
++ unsigned long tmo = ip_rt_gc_timeout;
++ unsigned long length;
++
++ i = (i + 1) & rt_hash_mask;
++ rthp = &rt_hash_table[i].chain;
++
++ if (need_resched())
++ cond_resched();
++
++ samples++;
++
++ if (rcu_dereference_raw(*rthp) == NULL)
++ continue;
++ length = 0;
++ spin_lock_bh(rt_hash_lock_addr(i));
++ while ((rth = rcu_dereference_protected(*rthp,
++ lockdep_is_held(rt_hash_lock_addr(i)))) != NULL) {
++ prefetch(rth->dst.rt_next);
++ if (rt_is_expired(rth)) {
++ *rthp = rth->dst.rt_next;
++ rt_free(rth);
++ continue;
++ }
++ if (rth->dst.expires) {
++ /* Entry is expired even if it is in use */
++ if (time_before_eq(jiffies, rth->dst.expires)) {
++nofree:
++ tmo >>= 1;
++ rthp = &rth->dst.rt_next;
++ /*
++ * We only count entries on
++ * a chain with equal hash inputs once
++ * so that entries for different QOS
++ * levels, and other non-hash input
++ * attributes don't unfairly skew
++ * the length computation
++ */
++ length += has_noalias(rt_hash_table[i].chain, rth);
++ continue;
++ }
++ } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout))
++ goto nofree;
++
++ /* Cleanup aged off entries. */
++ *rthp = rth->dst.rt_next;
++ rt_free(rth);
++ }
++ spin_unlock_bh(rt_hash_lock_addr(i));
++ sum += length;
++ sum2 += length*length;
++ }
++ if (samples) {
++ unsigned long avg = sum / samples;
++ unsigned long sd = int_sqrt(sum2 / samples - avg*avg);
++ rt_chain_length_max = max_t(unsigned long,
++ ip_rt_gc_elasticity,
++ (avg + 4*sd) >> FRACT_BITS);
++ }
++ rover = i;
++}
++
++/*
++ * rt_worker_func() is run in process context.
++ * we call rt_check_expire() to scan part of the hash table
++ */
++static void rt_worker_func(struct work_struct *work)
++{
++ rt_check_expire();
++ schedule_delayed_work(&expires_work, ip_rt_gc_interval);
++}
++
+ /*
+ * Perturbation of rt_genid by a small quantity [1..256]
+ * Using 8 bits of shuffling ensure we can call rt_cache_invalidate()
+@@ -3176,6 +3270,13 @@ static ctl_table ipv4_route_table[] = {
+ .proc_handler = proc_dointvec_jiffies,
+ },
+ {
++ .procname = "gc_interval",
++ .data = &ip_rt_gc_interval,
++ .maxlen = sizeof(int),
++ .mode = 0644,
++ .proc_handler = proc_dointvec_jiffies,
++ },
++ {
+ .procname = "redirect_load",
+ .data = &ip_rt_redirect_load,
+ .maxlen = sizeof(int),
+@@ -3385,6 +3486,11 @@ int __init ip_rt_init(void)
+ devinet_init();
+ ip_fib_init();
+
++ INIT_DELAYED_WORK_DEFERRABLE(&expires_work, rt_worker_func);
++ expires_ljiffies = jiffies;
++ schedule_delayed_work(&expires_work,
++ net_random() % ip_rt_gc_interval + ip_rt_gc_interval);
++
+ if (ip_rt_proc_init())
+ printk(KERN_ERR "Unable to create route proc files\n");
+ #ifdef CONFIG_XFRM
--- /dev/null
+From 31a4e30815354c5e49eb20752409ef7c721fc6b0 Mon Sep 17 00:00:00 2001
+From: Stephen Rothwell <sfr@canb.auug.org.au>
+Date: Thu, 22 Dec 2011 17:03:29 +1100
+Subject: ipv4: using prefetch requires including prefetch.h
+
+
+From: Stephen Rothwell <sfr@canb.auug.org.au>
+
+[ Upstream commit b9eda06f80b0db61a73bd87c6b0eb67d8aca55ad ]
+
+Signed-off-by: Stephen Rothwell <sfr@canb.auug.org.au>
+Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
+Acked-by: David Miller <davem@davemloft.net>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/ipv4/route.c | 1 +
+ 1 file changed, 1 insertion(+)
+
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -91,6 +91,7 @@
+ #include <linux/rcupdate.h>
+ #include <linux/times.h>
+ #include <linux/slab.h>
++#include <linux/prefetch.h>
+ #include <net/dst.h>
+ #include <net/net_namespace.h>
+ #include <net/protocol.h>
--- /dev/null
+From 5790d60ca9a1775b05c26da9f392a10234fd1ac7 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Tue, 13 Dec 2011 17:35:06 -0500
+Subject: ipv6: Check dest prefix length on original route not copied one in rt6_alloc_cow().
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit bb3c36863e8001fc21a88bebfdead4da4c23e848 ]
+
+After commit 8e2ec639173f325977818c45011ee176ef2b11f6 ("ipv6: don't
+use inetpeer to store metrics for routes.") the test in rt6_alloc_cow()
+for setting the ANYCAST flag is now wrong.
+
+'rt' will always now have a plen of 128, because it is set explicitly
+to 128 by ip6_rt_copy.
+
+So to restore the semantics of the test, check the destination prefix
+length of 'ort'.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/ipv6/route.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/ipv6/route.c
++++ b/net/ipv6/route.c
+@@ -725,7 +725,7 @@ static struct rt6_info *rt6_alloc_cow(co
+ int attempts = !in_softirq();
+
+ if (!(rt->rt6i_flags&RTF_GATEWAY)) {
+- if (rt->rt6i_dst.plen != 128 &&
++ if (ort->rt6i_dst.plen != 128 &&
+ ipv6_addr_equal(&ort->rt6i_dst.addr, daddr))
+ rt->rt6i_flags |= RTF_ANYCAST;
+ ipv6_addr_copy(&rt->rt6i_gateway, daddr);
--- /dev/null
+From 76bcc2af1348ccf5a40421e1181f2547718a1e51 Mon Sep 17 00:00:00 2001
+From: Alex Juncu <ajuncu@ixiacom.com>
+Date: Thu, 15 Dec 2011 23:01:25 +0000
+Subject: llc: llc_cmsg_rcv was getting called after sk_eat_skb.
+
+
+From: Alex Juncu <ajuncu@ixiacom.com>
+
+[ Upstream commit 9cef310fcdee12b49b8b4c96fd8f611c8873d284 ]
+
+Received non stream protocol packets were calling llc_cmsg_rcv that used a
+skb after that skb was released by sk_eat_skb. This caused received STP
+packets to generate kernel panics.
+
+Signed-off-by: Alexandru Juncu <ajuncu@ixiacom.com>
+Signed-off-by: Kunjan Naik <knaik@ixiacom.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/llc/af_llc.c | 14 ++++++++++----
+ 1 file changed, 10 insertions(+), 4 deletions(-)
+
+--- a/net/llc/af_llc.c
++++ b/net/llc/af_llc.c
+@@ -833,15 +833,15 @@ static int llc_ui_recvmsg(struct kiocb *
+ copied += used;
+ len -= used;
+
++ /* For non stream protcols we get one packet per recvmsg call */
++ if (sk->sk_type != SOCK_STREAM)
++ goto copy_uaddr;
++
+ if (!(flags & MSG_PEEK)) {
+ sk_eat_skb(sk, skb, 0);
+ *seq = 0;
+ }
+
+- /* For non stream protcols we get one packet per recvmsg call */
+- if (sk->sk_type != SOCK_STREAM)
+- goto copy_uaddr;
+-
+ /* Partial read */
+ if (used + offset < skb->len)
+ continue;
+@@ -857,6 +857,12 @@ copy_uaddr:
+ }
+ if (llc_sk(sk)->cmsg_flags)
+ llc_cmsg_rcv(msg, skb);
++
++ if (!(flags & MSG_PEEK)) {
++ sk_eat_skb(sk, skb, 0);
++ *seq = 0;
++ }
++
+ goto out;
+ }
+
--- /dev/null
+From 5e59a51890a259701718b9328560934407176b46 Mon Sep 17 00:00:00 2001
+From: Thomas Graf <tgraf@redhat.com>
+Date: Thu, 22 Dec 2011 02:05:07 +0000
+Subject: mqprio: Avoid panic if no options are provided
+
+
+From: Thomas Graf <tgraf@redhat.com>
+
+[ Upstream commit 7838f2ce36b6ab5c13ef20b1857e3bbd567f1759 ]
+
+Userspace may not provide TCA_OPTIONS, in fact tc currently does
+so not do so if no arguments are specified on the command line.
+Return EINVAL instead of panicing.
+
+Signed-off-by: Thomas Graf <tgraf@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/sched/sch_mqprio.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/sched/sch_mqprio.c
++++ b/net/sched/sch_mqprio.c
+@@ -106,7 +106,7 @@ static int mqprio_init(struct Qdisc *sch
+ if (!netif_is_multiqueue(dev))
+ return -EOPNOTSUPP;
+
+- if (nla_len(opt) < sizeof(*qopt))
++ if (!opt || nla_len(opt) < sizeof(*qopt))
+ return -EINVAL;
+
+ qopt = nla_data(opt);
--- /dev/null
+From fe032a0d6c13f13f66f7517ca72f2d8422333401 Mon Sep 17 00:00:00 2001
+From: Steffen Klassert <steffen.klassert@secunet.com>
+Date: Wed, 21 Dec 2011 16:48:08 -0500
+Subject: net: Add a flow_cache_flush_deferred function
+
+
+From: Steffen Klassert <steffen.klassert@secunet.com>
+
+[ Upstream commit c0ed1c14a72ca9ebacd51fb94a8aca488b0d361e ]
+
+flow_cach_flush() might sleep but can be called from
+atomic context via the xfrm garbage collector. So add
+a flow_cache_flush_deferred() function and use this if
+the xfrm garbage colector is invoked from within the
+packet path.
+
+Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
+Acked-by: Timo Teräs <timo.teras@iki.fi>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ include/net/flow.h | 1 +
+ net/core/flow.c | 12 ++++++++++++
+ net/xfrm/xfrm_policy.c | 18 ++++++++++++++----
+ 3 files changed, 27 insertions(+), 4 deletions(-)
+
+--- a/include/net/flow.h
++++ b/include/net/flow.h
+@@ -207,6 +207,7 @@ extern struct flow_cache_object *flow_ca
+ u8 dir, flow_resolve_t resolver, void *ctx);
+
+ extern void flow_cache_flush(void);
++extern void flow_cache_flush_deferred(void);
+ extern atomic_t flow_cache_genid;
+
+ #endif
+--- a/net/core/flow.c
++++ b/net/core/flow.c
+@@ -358,6 +358,18 @@ void flow_cache_flush(void)
+ put_online_cpus();
+ }
+
++static void flow_cache_flush_task(struct work_struct *work)
++{
++ flow_cache_flush();
++}
++
++static DECLARE_WORK(flow_cache_flush_work, flow_cache_flush_task);
++
++void flow_cache_flush_deferred(void)
++{
++ schedule_work(&flow_cache_flush_work);
++}
++
+ static int __cpuinit flow_cache_cpu_prepare(struct flow_cache *fc, int cpu)
+ {
+ struct flow_cache_percpu *fcp = per_cpu_ptr(fc->percpu, cpu);
+--- a/net/xfrm/xfrm_policy.c
++++ b/net/xfrm/xfrm_policy.c
+@@ -2276,8 +2276,6 @@ static void __xfrm_garbage_collect(struc
+ {
+ struct dst_entry *head, *next;
+
+- flow_cache_flush();
+-
+ spin_lock_bh(&xfrm_policy_sk_bundle_lock);
+ head = xfrm_policy_sk_bundles;
+ xfrm_policy_sk_bundles = NULL;
+@@ -2290,6 +2288,18 @@ static void __xfrm_garbage_collect(struc
+ }
+ }
+
++static void xfrm_garbage_collect(struct net *net)
++{
++ flow_cache_flush();
++ __xfrm_garbage_collect(net);
++}
++
++static void xfrm_garbage_collect_deferred(struct net *net)
++{
++ flow_cache_flush_deferred();
++ __xfrm_garbage_collect(net);
++}
++
+ static void xfrm_init_pmtu(struct dst_entry *dst)
+ {
+ do {
+@@ -2420,7 +2430,7 @@ int xfrm_policy_register_afinfo(struct x
+ if (likely(dst_ops->neigh_lookup == NULL))
+ dst_ops->neigh_lookup = xfrm_neigh_lookup;
+ if (likely(afinfo->garbage_collect == NULL))
+- afinfo->garbage_collect = __xfrm_garbage_collect;
++ afinfo->garbage_collect = xfrm_garbage_collect_deferred;
+ xfrm_policy_afinfo[afinfo->family] = afinfo;
+ }
+ write_unlock_bh(&xfrm_policy_afinfo_lock);
+@@ -2514,7 +2524,7 @@ static int xfrm_dev_event(struct notifie
+
+ switch (event) {
+ case NETDEV_DOWN:
+- __xfrm_garbage_collect(dev_net(dev));
++ xfrm_garbage_collect(dev_net(dev));
+ }
+ return NOTIFY_DONE;
+ }
--- /dev/null
+From c9443fa522619b70cc9ea12d7f58e4cf633500c3 Mon Sep 17 00:00:00 2001
+From: Markus Kötter <nepenthesdev@gmail.com>
+Date: Sat, 17 Dec 2011 11:39:08 +0000
+Subject: net: bpf_jit: fix an off-one bug in x86_64 cond jump target
+
+
+From: Markus Kötter <nepenthesdev@gmail.com>
+
+[ Upstream commit a03ffcf873fe0f2565386ca8ef832144c42e67fa ]
+
+x86 jump instruction size is 2 or 5 bytes (near/long jump), not 2 or 6
+bytes.
+
+In case a conditional jump is followed by a long jump, conditional jump
+target is one byte past the start of target instruction.
+
+Signed-off-by: Markus Kötter <nepenthesdev@gmail.com>
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/x86/net/bpf_jit_comp.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/x86/net/bpf_jit_comp.c
++++ b/arch/x86/net/bpf_jit_comp.c
+@@ -568,8 +568,8 @@ cond_branch: f_offset = addrs[i + filt
+ break;
+ }
+ if (filter[i].jt != 0) {
+- if (filter[i].jf)
+- t_offset += is_near(f_offset) ? 2 : 6;
++ if (filter[i].jf && f_offset)
++ t_offset += is_near(f_offset) ? 2 : 5;
+ EMIT_COND_JMP(t_op, t_offset);
+ if (filter[i].jf)
+ EMIT_JMP(f_offset);
--- /dev/null
+From 2ec3264c7298c2326f33c482e787ec449638ed85 Mon Sep 17 00:00:00 2001
+From: Gerlando Falauto <gerlando.falauto@keymile.com>
+Date: Mon, 19 Dec 2011 22:58:04 +0000
+Subject: net: have ipconfig not wait if no dev is available
+
+
+From: Gerlando Falauto <gerlando.falauto@keymile.com>
+
+[ Upstream commit cd7816d14953c8af910af5bb92f488b0b277e29d ]
+
+previous commit 3fb72f1e6e6165c5f495e8dc11c5bbd14c73385c
+makes IP-Config wait for carrier on at least one network device.
+
+Before waiting (predefined value 120s), check that at least one device
+was successfully brought up. Otherwise (e.g. buggy bootloader
+which does not set the MAC address) there is no point in waiting
+for carrier.
+
+Cc: Micha Nelissen <micha@neli.hopto.org>
+Cc: Holger Brunck <holger.brunck@keymile.com>
+Signed-off-by: Gerlando Falauto <gerlando.falauto@keymile.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/ipv4/ipconfig.c | 4 ++++
+ 1 file changed, 4 insertions(+)
+
+--- a/net/ipv4/ipconfig.c
++++ b/net/ipv4/ipconfig.c
+@@ -252,6 +252,10 @@ static int __init ic_open_devs(void)
+ }
+ }
+
++ /* no point in waiting if we could not bring up at least one device */
++ if (!ic_first_dev)
++ goto have_carrier;
++
+ /* wait for a carrier on at least one device */
+ start = jiffies;
+ while (jiffies - start < msecs_to_jiffies(CONF_CARRIER_TIMEOUT)) {
--- /dev/null
+From 214c4df6cf051ae163659e2b9e5ee200eed06688 Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Thu, 22 Dec 2011 04:15:53 +0000
+Subject: net: introduce DST_NOPEER dst flag
+
+
+From: Eric Dumazet <eric.dumazet@gmail.com>
+
+[ Upstream commit e688a604807647c9450f9c12a7cb6d027150a895 ]
+
+Chris Boot reported crashes occurring in ipv6_select_ident().
+
+[ 461.457562] RIP: 0010:[<ffffffff812dde61>] [<ffffffff812dde61>]
+ipv6_select_ident+0x31/0xa7
+
+[ 461.578229] Call Trace:
+[ 461.580742] <IRQ>
+[ 461.582870] [<ffffffff812efa7f>] ? udp6_ufo_fragment+0x124/0x1a2
+[ 461.589054] [<ffffffff812dbfe0>] ? ipv6_gso_segment+0xc0/0x155
+[ 461.595140] [<ffffffff812700c6>] ? skb_gso_segment+0x208/0x28b
+[ 461.601198] [<ffffffffa03f236b>] ? ipv6_confirm+0x146/0x15e
+[nf_conntrack_ipv6]
+[ 461.608786] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
+[ 461.614227] [<ffffffff81271d64>] ? dev_hard_start_xmit+0x357/0x543
+[ 461.620659] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
+[ 461.626440] [<ffffffffa0379745>] ? br_parse_ip_options+0x19a/0x19a
+[bridge]
+[ 461.633581] [<ffffffff812722ff>] ? dev_queue_xmit+0x3af/0x459
+[ 461.639577] [<ffffffffa03747d2>] ? br_dev_queue_push_xmit+0x72/0x76
+[bridge]
+[ 461.646887] [<ffffffffa03791e3>] ? br_nf_post_routing+0x17d/0x18f
+[bridge]
+[ 461.653997] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
+[ 461.659473] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
+[ 461.665485] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
+[ 461.671234] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
+[ 461.677299] [<ffffffffa0379215>] ?
+nf_bridge_update_protocol+0x20/0x20 [bridge]
+[ 461.684891] [<ffffffffa03bb0e5>] ? nf_ct_zone+0xa/0x17 [nf_conntrack]
+[ 461.691520] [<ffffffffa0374760>] ? br_flood+0xfa/0xfa [bridge]
+[ 461.697572] [<ffffffffa0374812>] ? NF_HOOK.constprop.8+0x3c/0x56
+[bridge]
+[ 461.704616] [<ffffffffa0379031>] ?
+nf_bridge_push_encap_header+0x1c/0x26 [bridge]
+[ 461.712329] [<ffffffffa037929f>] ? br_nf_forward_finish+0x8a/0x95
+[bridge]
+[ 461.719490] [<ffffffffa037900a>] ?
+nf_bridge_pull_encap_header+0x1c/0x27 [bridge]
+[ 461.727223] [<ffffffffa0379974>] ? br_nf_forward_ip+0x1c0/0x1d4 [bridge]
+[ 461.734292] [<ffffffff81291c4d>] ? nf_iterate+0x41/0x77
+[ 461.739758] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
+[ 461.746203] [<ffffffff81291cf6>] ? nf_hook_slow+0x73/0x111
+[ 461.751950] [<ffffffffa03748cc>] ? __br_deliver+0xa0/0xa0 [bridge]
+[ 461.758378] [<ffffffffa037533a>] ? NF_HOOK.constprop.4+0x56/0x56
+[bridge]
+
+This is caused by bridge netfilter special dst_entry (fake_rtable), a
+special shared entry, where attaching an inetpeer makes no sense.
+
+Problem is present since commit 87c48fa3b46 (ipv6: make fragment
+identifications less predictable)
+
+Introduce DST_NOPEER dst flag and make sure ipv6_select_ident() and
+__ip_select_ident() fallback to the 'no peer attached' handling.
+
+Reported-by: Chris Boot <bootc@bootc.net>
+Tested-by: Chris Boot <bootc@bootc.net>
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ include/net/dst.h | 1 +
+ net/bridge/br_netfilter.c | 2 +-
+ net/ipv4/route.c | 4 ++--
+ net/ipv6/ip6_output.c | 2 +-
+ 4 files changed, 5 insertions(+), 4 deletions(-)
+
+--- a/include/net/dst.h
++++ b/include/net/dst.h
+@@ -53,6 +53,7 @@ struct dst_entry {
+ #define DST_NOHASH 0x0008
+ #define DST_NOCACHE 0x0010
+ #define DST_NOCOUNT 0x0020
++#define DST_NOPEER 0x0040
+
+ short error;
+ short obsolete;
+--- a/net/bridge/br_netfilter.c
++++ b/net/bridge/br_netfilter.c
+@@ -141,7 +141,7 @@ void br_netfilter_rtable_init(struct net
+ rt->dst.dev = br->dev;
+ rt->dst.path = &rt->dst;
+ dst_init_metrics(&rt->dst, br_dst_default_metrics, true);
+- rt->dst.flags = DST_NOXFRM;
++ rt->dst.flags = DST_NOXFRM | DST_NOPEER;
+ rt->dst.ops = &fake_dst_ops;
+ }
+
+--- a/net/ipv4/route.c
++++ b/net/ipv4/route.c
+@@ -1272,7 +1272,7 @@ void __ip_select_ident(struct iphdr *iph
+ {
+ struct rtable *rt = (struct rtable *) dst;
+
+- if (rt) {
++ if (rt && !(rt->dst.flags & DST_NOPEER)) {
+ if (rt->peer == NULL)
+ rt_bind_peer(rt, rt->rt_dst, 1);
+
+@@ -1283,7 +1283,7 @@ void __ip_select_ident(struct iphdr *iph
+ iph->id = htons(inet_getid(rt->peer, more));
+ return;
+ }
+- } else
++ } else if (!rt)
+ printk(KERN_DEBUG "rt_bind_peer(0) @%p\n",
+ __builtin_return_address(0));
+
+--- a/net/ipv6/ip6_output.c
++++ b/net/ipv6/ip6_output.c
+@@ -606,7 +606,7 @@ void ipv6_select_ident(struct frag_hdr *
+ static atomic_t ipv6_fragmentation_id;
+ int old, new;
+
+- if (rt) {
++ if (rt && !(rt->dst.flags & DST_NOPEER)) {
+ struct inet_peer *peer;
+
+ if (!rt->rt6i_peer)
--- /dev/null
+From 884aad5cf67fed3cc15003dbb9c8cdf9b6833b57 Mon Sep 17 00:00:00 2001
+From: Djalal Harouni <tixxdz@opendz.org>
+Date: Tue, 6 Dec 2011 15:47:12 +0000
+Subject: ppp: fix pptp double release_sock in pptp_bind()
+
+
+From: Djalal Harouni <tixxdz@opendz.org>
+
+[ Upstream commit a454daceb78844a09c08b6e2d8badcb76a5d73b9 ]
+
+Signed-off-by: Djalal Harouni <tixxdz@opendz.org>
+Acked-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/net/pptp.c | 4 +---
+ 1 file changed, 1 insertion(+), 3 deletions(-)
+
+--- a/drivers/net/pptp.c
++++ b/drivers/net/pptp.c
+@@ -423,10 +423,8 @@ static int pptp_bind(struct socket *sock
+ lock_sock(sk);
+
+ opt->src_addr = sp->sa_addr.pptp;
+- if (add_chan(po)) {
+- release_sock(sk);
++ if (add_chan(po))
+ error = -EBUSY;
+- }
+
+ release_sock(sk);
+ return error;
--- /dev/null
+From 8c7968a17315bcfa4b907334a35675129d84025f Mon Sep 17 00:00:00 2001
+From: Eric Dumazet <eric.dumazet@gmail.com>
+Date: Sun, 11 Dec 2011 23:42:53 +0000
+Subject: sch_gred: should not use GFP_KERNEL while holding a spinlock
+
+
+From: Eric Dumazet <eric.dumazet@gmail.com>
+
+[ Upstream commit 3f1e6d3fd37bd4f25e5b19f1c7ca21850426c33f ]
+
+gred_change_vq() is called under sch_tree_lock(sch).
+
+This means a spinlock is held, and we are not allowed to sleep in this
+context.
+
+We might pre-allocate memory using GFP_KERNEL before taking spinlock,
+but this is not suitable for stable material.
+
+Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/sched/sch_gred.c | 2 +-
+ 1 file changed, 1 insertion(+), 1 deletion(-)
+
+--- a/net/sched/sch_gred.c
++++ b/net/sched/sch_gred.c
+@@ -385,7 +385,7 @@ static inline int gred_change_vq(struct
+ struct gred_sched_data *q;
+
+ if (table->tab[dp] == NULL) {
+- table->tab[dp] = kzalloc(sizeof(*q), GFP_KERNEL);
++ table->tab[dp] = kzalloc(sizeof(*q), GFP_ATOMIC);
+ if (table->tab[dp] == NULL)
+ return -ENOMEM;
+ }
--- /dev/null
+From 094b242b70f67ac3996934432f0a0d564e791cf6 Mon Sep 17 00:00:00 2001
+From: Thomas Graf <tgraf@redhat.com>
+Date: Mon, 19 Dec 2011 04:11:40 +0000
+Subject: sctp: Do not account for sizeof(struct sk_buff) in estimated rwnd
+
+
+From: Thomas Graf <tgraf@redhat.com>
+
+[ Upstream commit a76c0adf60f6ca5ff3481992e4ea0383776b24d2 ]
+
+When checking whether a DATA chunk fits into the estimated rwnd a
+full sizeof(struct sk_buff) is added to the needed chunk size. This
+quickly exhausts the available rwnd space and leads to packets being
+sent which are much below the PMTU limit. This can lead to much worse
+performance.
+
+The reason for this behaviour was to avoid putting too much memory
+pressure on the receiver. The concept is not completely irational
+because a Linux receiver does in fact clone an skb for each DATA chunk
+delivered. However, Linux also reserves half the available socket
+buffer space for data structures therefore usage of it is already
+accounted for.
+
+When proposing to change this the last time it was noted that this
+behaviour was introduced to solve a performance issue caused by rwnd
+overusage in combination with small DATA chunks.
+
+Trying to reproduce this I found that with the sk_buff overhead removed,
+the performance would improve significantly unless socket buffer limits
+are increased.
+
+The following numbers have been gathered using a patched iperf
+supporting SCTP over a live 1 Gbit ethernet network. The -l option
+was used to limit DATA chunk sizes. The numbers listed are based on
+the average of 3 test runs each. Default values have been used for
+sk_(r|w)mem.
+
+Chunk
+Size Unpatched No Overhead
+-------------------------------------
+ 4 15.2 Kbit [!] 12.2 Mbit [!]
+ 8 35.8 Kbit [!] 26.0 Mbit [!]
+ 16 95.5 Kbit [!] 54.4 Mbit [!]
+ 32 106.7 Mbit 102.3 Mbit
+ 64 189.2 Mbit 188.3 Mbit
+ 128 331.2 Mbit 334.8 Mbit
+ 256 537.7 Mbit 536.0 Mbit
+ 512 766.9 Mbit 766.6 Mbit
+1024 810.1 Mbit 808.6 Mbit
+
+Signed-off-by: Thomas Graf <tgraf@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ net/sctp/output.c | 8 +-------
+ net/sctp/outqueue.c | 6 ++----
+ 2 files changed, 3 insertions(+), 11 deletions(-)
+
+--- a/net/sctp/output.c
++++ b/net/sctp/output.c
+@@ -697,13 +697,7 @@ static void sctp_packet_append_data(stru
+ /* Keep track of how many bytes are in flight to the receiver. */
+ asoc->outqueue.outstanding_bytes += datasize;
+
+- /* Update our view of the receiver's rwnd. Include sk_buff overhead
+- * while updating peer.rwnd so that it reduces the chances of a
+- * receiver running out of receive buffer space even when receive
+- * window is still open. This can happen when a sender is sending
+- * sending small messages.
+- */
+- datasize += sizeof(struct sk_buff);
++ /* Update our view of the receiver's rwnd. */
+ if (datasize < rwnd)
+ rwnd -= datasize;
+ else
+--- a/net/sctp/outqueue.c
++++ b/net/sctp/outqueue.c
+@@ -411,8 +411,7 @@ void sctp_retransmit_mark(struct sctp_ou
+ chunk->transport->flight_size -=
+ sctp_data_size(chunk);
+ q->outstanding_bytes -= sctp_data_size(chunk);
+- q->asoc->peer.rwnd += (sctp_data_size(chunk) +
+- sizeof(struct sk_buff));
++ q->asoc->peer.rwnd += sctp_data_size(chunk);
+ }
+ continue;
+ }
+@@ -432,8 +431,7 @@ void sctp_retransmit_mark(struct sctp_ou
+ * (Section 7.2.4)), add the data size of those
+ * chunks to the rwnd.
+ */
+- q->asoc->peer.rwnd += (sctp_data_size(chunk) +
+- sizeof(struct sk_buff));
++ q->asoc->peer.rwnd += sctp_data_size(chunk);
+ q->outstanding_bytes -= sctp_data_size(chunk);
+ if (chunk->transport)
+ transport->flight_size -= sctp_data_size(chunk);
--- /dev/null
+From 4dff6c35f9ff1cf62dd4435517adae40a3dd2d8a Mon Sep 17 00:00:00 2001
+From: Xi Wang <xi.wang@gmail.com>
+Date: Fri, 16 Dec 2011 12:44:15 +0000
+Subject: sctp: fix incorrect overflow check on autoclose
+
+
+From: Xi Wang <xi.wang@gmail.com>
+
+[ Upstream commit 2692ba61a82203404abd7dd2a027bda962861f74 ]
+
+Commit 8ffd3208 voids the previous patches f6778aab and 810c0719 for
+limiting the autoclose value. If userspace passes in -1 on 32-bit
+platform, the overflow check didn't work and autoclose would be set
+to 0xffffffff.
+
+This patch defines a max_autoclose (in seconds) for limiting the value
+and exposes it through sysctl, with the following intentions.
+
+1) Avoid overflowing autoclose * HZ.
+
+2) Keep the default autoclose bound consistent across 32- and 64-bit
+ platforms (INT_MAX / HZ in this patch).
+
+3) Keep the autoclose value consistent between setsockopt() and
+ getsockopt() calls.
+
+Suggested-by: Vlad Yasevich <vladislav.yasevich@hp.com>
+Signed-off-by: Xi Wang <xi.wang@gmail.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ include/net/sctp/structs.h | 4 ++++
+ net/sctp/associola.c | 2 +-
+ net/sctp/protocol.c | 3 +++
+ net/sctp/socket.c | 2 --
+ net/sctp/sysctl.c | 13 +++++++++++++
+ 5 files changed, 21 insertions(+), 3 deletions(-)
+
+--- a/include/net/sctp/structs.h
++++ b/include/net/sctp/structs.h
+@@ -241,6 +241,9 @@ extern struct sctp_globals {
+ * bits is an indicator of when to send and window update SACK.
+ */
+ int rwnd_update_shift;
++
++ /* Threshold for autoclose timeout, in seconds. */
++ unsigned long max_autoclose;
+ } sctp_globals;
+
+ #define sctp_rto_initial (sctp_globals.rto_initial)
+@@ -281,6 +284,7 @@ extern struct sctp_globals {
+ #define sctp_auth_enable (sctp_globals.auth_enable)
+ #define sctp_checksum_disable (sctp_globals.checksum_disable)
+ #define sctp_rwnd_upd_shift (sctp_globals.rwnd_update_shift)
++#define sctp_max_autoclose (sctp_globals.max_autoclose)
+
+ /* SCTP Socket type: UDP or TCP style. */
+ typedef enum {
+--- a/net/sctp/associola.c
++++ b/net/sctp/associola.c
+@@ -173,7 +173,7 @@ static struct sctp_association *sctp_ass
+ asoc->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] = 0;
+ asoc->timeouts[SCTP_EVENT_TIMEOUT_SACK] = asoc->sackdelay;
+ asoc->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
+- (unsigned long)sp->autoclose * HZ;
++ min_t(unsigned long, sp->autoclose, sctp_max_autoclose) * HZ;
+
+ /* Initializes the timers */
+ for (i = SCTP_EVENT_TIMEOUT_NONE; i < SCTP_NUM_TIMEOUT_TYPES; ++i)
+--- a/net/sctp/protocol.c
++++ b/net/sctp/protocol.c
+@@ -1285,6 +1285,9 @@ SCTP_STATIC __init int sctp_init(void)
+ sctp_max_instreams = SCTP_DEFAULT_INSTREAMS;
+ sctp_max_outstreams = SCTP_DEFAULT_OUTSTREAMS;
+
++ /* Initialize maximum autoclose timeout. */
++ sctp_max_autoclose = INT_MAX / HZ;
++
+ /* Initialize handle used for association ids. */
+ idr_init(&sctp_assocs_id);
+
+--- a/net/sctp/socket.c
++++ b/net/sctp/socket.c
+@@ -2199,8 +2199,6 @@ static int sctp_setsockopt_autoclose(str
+ return -EINVAL;
+ if (copy_from_user(&sp->autoclose, optval, optlen))
+ return -EFAULT;
+- /* make sure it won't exceed MAX_SCHEDULE_TIMEOUT */
+- sp->autoclose = min_t(long, sp->autoclose, MAX_SCHEDULE_TIMEOUT / HZ);
+
+ return 0;
+ }
+--- a/net/sctp/sysctl.c
++++ b/net/sctp/sysctl.c
+@@ -53,6 +53,10 @@ static int sack_timer_min = 1;
+ static int sack_timer_max = 500;
+ static int addr_scope_max = 3; /* check sctp_scope_policy_t in include/net/sctp/constants.h for max entries */
+ static int rwnd_scale_max = 16;
++static unsigned long max_autoclose_min = 0;
++static unsigned long max_autoclose_max =
++ (MAX_SCHEDULE_TIMEOUT / HZ > UINT_MAX)
++ ? UINT_MAX : MAX_SCHEDULE_TIMEOUT / HZ;
+
+ extern long sysctl_sctp_mem[3];
+ extern int sysctl_sctp_rmem[3];
+@@ -258,6 +262,15 @@ static ctl_table sctp_table[] = {
+ .extra1 = &one,
+ .extra2 = &rwnd_scale_max,
+ },
++ {
++ .procname = "max_autoclose",
++ .data = &sctp_max_autoclose,
++ .maxlen = sizeof(unsigned long),
++ .mode = 0644,
++ .proc_handler = &proc_doulongvec_minmax,
++ .extra1 = &max_autoclose_min,
++ .extra2 = &max_autoclose_max,
++ },
+
+ { /* sentinel */ }
+ };
mm-hugetlb-fix-non-atomic-enqueue-of-huge-page.patch
mm-mempolicy.c-refix-mbind_range-vma-issue.patch
mpt2sas-crashes-on-shutdown.patch
+sparc64-fix-msiq-hv-call-ordering-in-pci_sun4v_msiq_build_irq.patch
+sparc32-be-less-strict-in-matching-lo-part-of-relocation.patch
+sparc64-patch-sun4v-code-sequences-properly-on-module-load.patch
+sparc-kill-custom-io_remap_pfn_range.patch
+sparc32-remove-non-kernel-code-from-memcpy-implementation.patch
+sparc32-remove-uses-of-g7-in-memcpy-implementation.patch
+sparc32-correct-the-return-value-of-memcpy.patch
+sparc64-fix-masking-and-shifting-in-vis-fpcmp-emulation.patch
+sparc-fix-handling-of-orig_i0-wrt.-debugging-when-restarting-syscalls.patch
+net-bpf_jit-fix-an-off-one-bug-in-x86_64-cond-jump-target.patch
+ppp-fix-pptp-double-release_sock-in-pptp_bind.patch
+llc-llc_cmsg_rcv-was-getting-called-after-sk_eat_skb.patch
+mqprio-avoid-panic-if-no-options-are-provided.patch
+net-have-ipconfig-not-wait-if-no-dev-is-available.patch
+sch_gred-should-not-use-gfp_kernel-while-holding-a-spinlock.patch
+sctp-fix-incorrect-overflow-check-on-autoclose.patch
+sctp-do-not-account-for-sizeof-struct-sk_buff-in-estimated-rwnd.patch
+net-add-a-flow_cache_flush_deferred-function.patch
+ipv4-flush-route-cache-after-change-accept_local.patch
+ipv6-check-dest-prefix-length-on-original-route-not-copied-one-in-rt6_alloc_cow.patch
+net-introduce-dst_nopeer-dst-flag.patch
+ipv4-reintroduce-route-cache-garbage-collector.patch
+ipv4-using-prefetch-requires-including-prefetch.h.patch
--- /dev/null
+From b167cbdeb37906bc30c1a618202e43373f96d09a Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Mon, 26 Dec 2011 12:30:13 -0500
+Subject: sparc: Fix handling of orig_i0 wrt. debugging when restarting syscalls.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ A combination of upstream commits 1d299bc7732c34d85bd43ac1a8745f5a2fed2078 and
+ e88d2468718b0789b4c33da2f7e1cef2a1eee279 ]
+
+Although we provide a proper way for a debugger to control whether
+syscall restart occurs, we run into problems because orig_i0 is not
+saved and restored properly.
+
+Luckily we can solve this problem without having to make debuggers
+aware of the issue. Across system calls, several registers are
+considered volatile and can be safely clobbered.
+
+Therefore we use the pt_regs save area of one of those registers, %g6,
+as a place to save and restore orig_i0.
+
+Debuggers transparently will do the right thing because they save and
+restore this register already.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/kernel/signal32.c | 18 ++++++++++--------
+ arch/sparc/kernel/signal_32.c | 30 +++++++++++++++++++++++++-----
+ arch/sparc/kernel/signal_64.c | 42 ++++++++++++++++++++++++++++--------------
+ 3 files changed, 63 insertions(+), 27 deletions(-)
+
+--- a/arch/sparc/kernel/signal32.c
++++ b/arch/sparc/kernel/signal32.c
+@@ -822,21 +822,23 @@ static inline void syscall_restart32(uns
+ * want to handle. Thus you cannot kill init even with a SIGKILL even by
+ * mistake.
+ */
+-void do_signal32(sigset_t *oldset, struct pt_regs * regs,
+- int restart_syscall, unsigned long orig_i0)
++void do_signal32(sigset_t *oldset, struct pt_regs * regs)
+ {
+ struct k_sigaction ka;
++ unsigned long orig_i0;
++ int restart_syscall;
+ siginfo_t info;
+ int signr;
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+- /* If the debugger messes with the program counter, it clears
+- * the "in syscall" bit, directing us to not perform a syscall
+- * restart.
+- */
+- if (restart_syscall && !pt_regs_is_syscall(regs))
+- restart_syscall = 0;
++ restart_syscall = 0;
++ orig_i0 = 0;
++ if (pt_regs_is_syscall(regs) &&
++ (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
++ restart_syscall = 1;
++ orig_i0 = regs->u_regs[UREG_G6];
++ }
+
+ if (signr > 0) {
+ if (restart_syscall)
+--- a/arch/sparc/kernel/signal_32.c
++++ b/arch/sparc/kernel/signal_32.c
+@@ -519,10 +519,26 @@ static void do_signal(struct pt_regs *re
+ siginfo_t info;
+ int signr;
+
++ /* It's a lot of work and synchronization to add a new ptrace
++ * register for GDB to save and restore in order to get
++ * orig_i0 correct for syscall restarts when debugging.
++ *
++ * Although it should be the case that most of the global
++ * registers are volatile across a system call, glibc already
++ * depends upon that fact that we preserve them. So we can't
++ * just use any global register to save away the orig_i0 value.
++ *
++ * In particular %g2, %g3, %g4, and %g5 are all assumed to be
++ * preserved across a system call trap by various pieces of
++ * code in glibc.
++ *
++ * %g7 is used as the "thread register". %g6 is not used in
++ * any fixed manner. %g6 is used as a scratch register and
++ * a compiler temporary, but it's value is never used across
++ * a system call. Therefore %g6 is usable for orig_i0 storage.
++ */
+ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C))
+- restart_syscall = 1;
+- else
+- restart_syscall = 0;
++ regs->u_regs[UREG_G6] = orig_i0;
+
+ if (test_thread_flag(TIF_RESTORE_SIGMASK))
+ oldset = ¤t->saved_sigmask;
+@@ -535,8 +551,12 @@ static void do_signal(struct pt_regs *re
+ * the software "in syscall" bit, directing us to not perform
+ * a syscall restart.
+ */
+- if (restart_syscall && !pt_regs_is_syscall(regs))
+- restart_syscall = 0;
++ restart_syscall = 0;
++ if (pt_regs_is_syscall(regs) && (regs->psr & PSR_C)) {
++ restart_syscall = 1;
++ orig_i0 = regs->u_regs[UREG_G6];
++ }
++
+
+ if (signr > 0) {
+ if (restart_syscall)
+--- a/arch/sparc/kernel/signal_64.c
++++ b/arch/sparc/kernel/signal_64.c
+@@ -529,11 +529,27 @@ static void do_signal(struct pt_regs *re
+ siginfo_t info;
+ int signr;
+
++ /* It's a lot of work and synchronization to add a new ptrace
++ * register for GDB to save and restore in order to get
++ * orig_i0 correct for syscall restarts when debugging.
++ *
++ * Although it should be the case that most of the global
++ * registers are volatile across a system call, glibc already
++ * depends upon that fact that we preserve them. So we can't
++ * just use any global register to save away the orig_i0 value.
++ *
++ * In particular %g2, %g3, %g4, and %g5 are all assumed to be
++ * preserved across a system call trap by various pieces of
++ * code in glibc.
++ *
++ * %g7 is used as the "thread register". %g6 is not used in
++ * any fixed manner. %g6 is used as a scratch register and
++ * a compiler temporary, but it's value is never used across
++ * a system call. Therefore %g6 is usable for orig_i0 storage.
++ */
+ if (pt_regs_is_syscall(regs) &&
+- (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
+- restart_syscall = 1;
+- } else
+- restart_syscall = 0;
++ (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY)))
++ regs->u_regs[UREG_G6] = orig_i0;
+
+ if (current_thread_info()->status & TS_RESTORE_SIGMASK)
+ oldset = ¤t->saved_sigmask;
+@@ -542,22 +558,20 @@ static void do_signal(struct pt_regs *re
+
+ #ifdef CONFIG_COMPAT
+ if (test_thread_flag(TIF_32BIT)) {
+- extern void do_signal32(sigset_t *, struct pt_regs *,
+- int restart_syscall,
+- unsigned long orig_i0);
+- do_signal32(oldset, regs, restart_syscall, orig_i0);
++ extern void do_signal32(sigset_t *, struct pt_regs *);
++ do_signal32(oldset, regs);
+ return;
+ }
+ #endif
+
+ signr = get_signal_to_deliver(&info, &ka, regs, NULL);
+
+- /* If the debugger messes with the program counter, it clears
+- * the software "in syscall" bit, directing us to not perform
+- * a syscall restart.
+- */
+- if (restart_syscall && !pt_regs_is_syscall(regs))
+- restart_syscall = 0;
++ restart_syscall = 0;
++ if (pt_regs_is_syscall(regs) &&
++ (regs->tstate & (TSTATE_XCARRY | TSTATE_ICARRY))) {
++ restart_syscall = 1;
++ orig_i0 = regs->u_regs[UREG_G6];
++ }
+
+ if (signr > 0) {
+ if (restart_syscall)
--- /dev/null
+From 14e707a033b1266711adacb4629e7548e31a38e2 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Thu, 17 Nov 2011 18:17:59 -0800
+Subject: sparc: Kill custom io_remap_pfn_range().
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 3e37fd3153ac95088a74f5e7c569f7567e9f993a ]
+
+To handle the large physical addresses, just make a simple wrapper
+around remap_pfn_range() like MIPS does.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/include/asm/pgtable_32.h | 20 +++-
+ arch/sparc/include/asm/pgtable_64.h | 20 +++-
+ arch/sparc/mm/Makefile | 1
+ arch/sparc/mm/generic_32.c | 98 ---------------------
+ arch/sparc/mm/generic_64.c | 164 ------------------------------------
+ 5 files changed, 32 insertions(+), 271 deletions(-)
+ delete mode 100644 arch/sparc/mm/generic_32.c
+ delete mode 100644 arch/sparc/mm/generic_64.c
+
+--- a/arch/sparc/include/asm/pgtable_32.h
++++ b/arch/sparc/include/asm/pgtable_32.h
+@@ -431,10 +431,6 @@ extern unsigned long *sparc_valid_addr_b
+ #define kern_addr_valid(addr) \
+ (test_bit(__pa((unsigned long)(addr))>>20, sparc_valid_addr_bitmap))
+
+-extern int io_remap_pfn_range(struct vm_area_struct *vma,
+- unsigned long from, unsigned long pfn,
+- unsigned long size, pgprot_t prot);
+-
+ /*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits. These macros/functions put it there or get it from there.
+@@ -443,6 +439,22 @@ extern int io_remap_pfn_range(struct vm_
+ #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4))
+ #define GET_PFN(pfn) (pfn & 0x0fffffffUL)
+
++extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
++ unsigned long, pgprot_t);
++
++static inline int io_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long from, unsigned long pfn,
++ unsigned long size, pgprot_t prot)
++{
++ unsigned long long offset, space, phys_base;
++
++ offset = ((unsigned long long) GET_PFN(pfn)) << PAGE_SHIFT;
++ space = GET_IOSPACE(pfn);
++ phys_base = offset | (space << 32ULL);
++
++ return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
++}
++
+ #define __HAVE_ARCH_PTEP_SET_ACCESS_FLAGS
+ #define ptep_set_access_flags(__vma, __address, __ptep, __entry, __dirty) \
+ ({ \
+--- a/arch/sparc/include/asm/pgtable_64.h
++++ b/arch/sparc/include/asm/pgtable_64.h
+@@ -757,10 +757,6 @@ static inline bool kern_addr_valid(unsig
+
+ extern int page_in_phys_avail(unsigned long paddr);
+
+-extern int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+- unsigned long pfn,
+- unsigned long size, pgprot_t prot);
+-
+ /*
+ * For sparc32&64, the pfn in io_remap_pfn_range() carries <iospace> in
+ * its high 4 bits. These macros/functions put it there or get it from there.
+@@ -769,6 +765,22 @@ extern int io_remap_pfn_range(struct vm_
+ #define GET_IOSPACE(pfn) (pfn >> (BITS_PER_LONG - 4))
+ #define GET_PFN(pfn) (pfn & 0x0fffffffffffffffUL)
+
++extern int remap_pfn_range(struct vm_area_struct *, unsigned long, unsigned long,
++ unsigned long, pgprot_t);
++
++static inline int io_remap_pfn_range(struct vm_area_struct *vma,
++ unsigned long from, unsigned long pfn,
++ unsigned long size, pgprot_t prot)
++{
++ unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
++ int space = GET_IOSPACE(pfn);
++ unsigned long phys_base;
++
++ phys_base = offset | (((unsigned long) space) << 32UL);
++
++ return remap_pfn_range(vma, from, phys_base >> PAGE_SHIFT, size, prot);
++}
++
+ #include <asm-generic/pgtable.h>
+
+ /* We provide our own get_unmapped_area to cope with VA holes and
+--- a/arch/sparc/mm/Makefile
++++ b/arch/sparc/mm/Makefile
+@@ -8,7 +8,6 @@ obj-$(CONFIG_SPARC64) += ultra.o tlb.o
+ obj-y += fault_$(BITS).o
+ obj-y += init_$(BITS).o
+ obj-$(CONFIG_SPARC32) += loadmmu.o
+-obj-y += generic_$(BITS).o
+ obj-$(CONFIG_SPARC32) += extable.o btfixup.o srmmu.o iommu.o io-unit.o
+ obj-$(CONFIG_SPARC32) += hypersparc.o viking.o tsunami.o swift.o
+ obj-$(CONFIG_SPARC_LEON)+= leon_mm.o
+--- a/arch/sparc/mm/generic_32.c
++++ /dev/null
+@@ -1,98 +0,0 @@
+-/*
+- * generic.c: Generic Sparc mm routines that are not dependent upon
+- * MMU type but are Sparc specific.
+- *
+- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/swap.h>
+-#include <linux/pagemap.h>
+-
+-#include <asm/pgalloc.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-#include <asm/cacheflush.h>
+-#include <asm/tlbflush.h>
+-
+-/* Remap IO memory, the same way as remap_pfn_range(), but use
+- * the obio memory space.
+- *
+- * They use a pgprot that sets PAGE_IO and does not check the
+- * mem_map table as this is independent of normal memory.
+- */
+-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte, unsigned long address, unsigned long size,
+- unsigned long offset, pgprot_t prot, int space)
+-{
+- unsigned long end;
+-
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- do {
+- set_pte_at(mm, address, pte, mk_pte_io(offset, prot, space));
+- address += PAGE_SIZE;
+- offset += PAGE_SIZE;
+- pte++;
+- } while (address < end);
+-}
+-
+-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long offset, pgprot_t prot, int space)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- offset -= address;
+- do {
+- pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address < end);
+- return 0;
+-}
+-
+-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+- unsigned long pfn, unsigned long size, pgprot_t prot)
+-{
+- int error = 0;
+- pgd_t * dir;
+- unsigned long beg = from;
+- unsigned long end = from + size;
+- struct mm_struct *mm = vma->vm_mm;
+- int space = GET_IOSPACE(pfn);
+- unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+-
+- /* See comment in mm/memory.c remap_pfn_range */
+- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+- vma->vm_pgoff = (offset >> PAGE_SHIFT) |
+- ((unsigned long)space << 28UL);
+-
+- offset -= from;
+- dir = pgd_offset(mm, from);
+- flush_cache_range(vma, beg, end);
+-
+- while (from < end) {
+- pmd_t *pmd = pmd_alloc(mm, dir, from);
+- error = -ENOMEM;
+- if (!pmd)
+- break;
+- error = io_remap_pmd_range(mm, pmd, from, end - from, offset + from, prot, space);
+- if (error)
+- break;
+- from = (from + PGDIR_SIZE) & PGDIR_MASK;
+- dir++;
+- }
+-
+- flush_tlb_range(vma, beg, end);
+- return error;
+-}
+-EXPORT_SYMBOL(io_remap_pfn_range);
+--- a/arch/sparc/mm/generic_64.c
++++ /dev/null
+@@ -1,164 +0,0 @@
+-/*
+- * generic.c: Generic Sparc mm routines that are not dependent upon
+- * MMU type but are Sparc specific.
+- *
+- * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+- */
+-
+-#include <linux/kernel.h>
+-#include <linux/mm.h>
+-#include <linux/swap.h>
+-#include <linux/pagemap.h>
+-
+-#include <asm/pgalloc.h>
+-#include <asm/pgtable.h>
+-#include <asm/page.h>
+-#include <asm/tlbflush.h>
+-
+-/* Remap IO memory, the same way as remap_pfn_range(), but use
+- * the obio memory space.
+- *
+- * They use a pgprot that sets PAGE_IO and does not check the
+- * mem_map table as this is independent of normal memory.
+- */
+-static inline void io_remap_pte_range(struct mm_struct *mm, pte_t * pte,
+- unsigned long address,
+- unsigned long size,
+- unsigned long offset, pgprot_t prot,
+- int space)
+-{
+- unsigned long end;
+-
+- /* clear hack bit that was used as a write_combine side-effect flag */
+- offset &= ~0x1UL;
+- address &= ~PMD_MASK;
+- end = address + size;
+- if (end > PMD_SIZE)
+- end = PMD_SIZE;
+- do {
+- pte_t entry;
+- unsigned long curend = address + PAGE_SIZE;
+-
+- entry = mk_pte_io(offset, prot, space, PAGE_SIZE);
+- if (!(address & 0xffff)) {
+- if (PAGE_SIZE < (4 * 1024 * 1024) &&
+- !(address & 0x3fffff) &&
+- !(offset & 0x3ffffe) &&
+- end >= address + 0x400000) {
+- entry = mk_pte_io(offset, prot, space,
+- 4 * 1024 * 1024);
+- curend = address + 0x400000;
+- offset += 0x400000;
+- } else if (PAGE_SIZE < (512 * 1024) &&
+- !(address & 0x7ffff) &&
+- !(offset & 0x7fffe) &&
+- end >= address + 0x80000) {
+- entry = mk_pte_io(offset, prot, space,
+- 512 * 1024 * 1024);
+- curend = address + 0x80000;
+- offset += 0x80000;
+- } else if (PAGE_SIZE < (64 * 1024) &&
+- !(offset & 0xfffe) &&
+- end >= address + 0x10000) {
+- entry = mk_pte_io(offset, prot, space,
+- 64 * 1024);
+- curend = address + 0x10000;
+- offset += 0x10000;
+- } else
+- offset += PAGE_SIZE;
+- } else
+- offset += PAGE_SIZE;
+-
+- if (pte_write(entry))
+- entry = pte_mkdirty(entry);
+- do {
+- BUG_ON(!pte_none(*pte));
+- set_pte_at(mm, address, pte, entry);
+- address += PAGE_SIZE;
+- pte_val(entry) += PAGE_SIZE;
+- pte++;
+- } while (address < curend);
+- } while (address < end);
+-}
+-
+-static inline int io_remap_pmd_range(struct mm_struct *mm, pmd_t * pmd, unsigned long address, unsigned long size,
+- unsigned long offset, pgprot_t prot, int space)
+-{
+- unsigned long end;
+-
+- address &= ~PGDIR_MASK;
+- end = address + size;
+- if (end > PGDIR_SIZE)
+- end = PGDIR_SIZE;
+- offset -= address;
+- do {
+- pte_t *pte = pte_alloc_map(mm, NULL, pmd, address);
+- if (!pte)
+- return -ENOMEM;
+- io_remap_pte_range(mm, pte, address, end - address, address + offset, prot, space);
+- pte_unmap(pte);
+- address = (address + PMD_SIZE) & PMD_MASK;
+- pmd++;
+- } while (address < end);
+- return 0;
+-}
+-
+-static inline int io_remap_pud_range(struct mm_struct *mm, pud_t * pud, unsigned long address, unsigned long size,
+- unsigned long offset, pgprot_t prot, int space)
+-{
+- unsigned long end;
+-
+- address &= ~PUD_MASK;
+- end = address + size;
+- if (end > PUD_SIZE)
+- end = PUD_SIZE;
+- offset -= address;
+- do {
+- pmd_t *pmd = pmd_alloc(mm, pud, address);
+- if (!pud)
+- return -ENOMEM;
+- io_remap_pmd_range(mm, pmd, address, end - address, address + offset, prot, space);
+- address = (address + PUD_SIZE) & PUD_MASK;
+- pud++;
+- } while (address < end);
+- return 0;
+-}
+-
+-int io_remap_pfn_range(struct vm_area_struct *vma, unsigned long from,
+- unsigned long pfn, unsigned long size, pgprot_t prot)
+-{
+- int error = 0;
+- pgd_t * dir;
+- unsigned long beg = from;
+- unsigned long end = from + size;
+- struct mm_struct *mm = vma->vm_mm;
+- int space = GET_IOSPACE(pfn);
+- unsigned long offset = GET_PFN(pfn) << PAGE_SHIFT;
+- unsigned long phys_base;
+-
+- phys_base = offset | (((unsigned long) space) << 32UL);
+-
+- /* See comment in mm/memory.c remap_pfn_range */
+- vma->vm_flags |= VM_IO | VM_RESERVED | VM_PFNMAP;
+- vma->vm_pgoff = phys_base >> PAGE_SHIFT;
+-
+- offset -= from;
+- dir = pgd_offset(mm, from);
+- flush_cache_range(vma, beg, end);
+-
+- while (from < end) {
+- pud_t *pud = pud_alloc(mm, dir, from);
+- error = -ENOMEM;
+- if (!pud)
+- break;
+- error = io_remap_pud_range(mm, pud, from, end - from, offset + from, prot, space);
+- if (error)
+- break;
+- from = (from + PGDIR_SIZE) & PGDIR_MASK;
+- dir++;
+- }
+-
+- flush_tlb_range(vma, beg, end);
+- return error;
+-}
+-EXPORT_SYMBOL(io_remap_pfn_range);
--- /dev/null
+From 20ef5b3fb98a8548235689c61080a7389a41145c Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Wed, 14 Dec 2011 10:05:22 -0800
+Subject: sparc32: Be less strict in matching %lo part of relocation.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit b1f44e13a525d2ffb7d5afe2273b7169d6f2222e ]
+
+The "(insn & 0x01800000) != 0x01800000" test matches 'restore'
+but that is a legitimate place to see the %lo() part of a 32-bit
+symbol relocation, particularly in tail calls.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Tested-by: Sergei Trofimovich <slyfox@gentoo.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/mm/btfixup.c | 3 +--
+ 1 file changed, 1 insertion(+), 2 deletions(-)
+
+--- a/arch/sparc/mm/btfixup.c
++++ b/arch/sparc/mm/btfixup.c
+@@ -302,8 +302,7 @@ void __init btfixup(void)
+ case 'i': /* INT */
+ if ((insn & 0xc1c00000) == 0x01000000) /* %HI */
+ set_addr(addr, q[1], fmangled, (insn & 0xffc00000) | (p[1] >> 10));
+- else if ((insn & 0x80002000) == 0x80002000 &&
+- (insn & 0x01800000) != 0x01800000) /* %LO */
++ else if ((insn & 0x80002000) == 0x80002000) /* %LO */
+ set_addr(addr, q[1], fmangled, (insn & 0xffffe000) | (p[1] & 0x3ff));
+ else {
+ prom_printf(insn_i, p, addr, insn);
--- /dev/null
+From 6bf220cd94d4ac023e1ad81ad2ad76f176d45892 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Wed, 19 Oct 2011 15:31:55 -0700
+Subject: sparc32: Correct the return value of memcpy.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit a52312b88c8103e965979a79a07f6b34af82ca4b ]
+
+Properly return the original destination buffer pointer.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Tested-by: Kjetil Oftedal <oftedal@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/lib/memcpy.S | 22 +++++++---------------
+ 1 file changed, 7 insertions(+), 15 deletions(-)
+
+--- a/arch/sparc/lib/memcpy.S
++++ b/arch/sparc/lib/memcpy.S
+@@ -13,14 +13,6 @@
+ .align 4; \
+ x:
+
+-
+-/* In kernel these functions don't return a value.
+- * One should use macros in asm/string.h for that purpose.
+- * We return 0, so that bugs are more apparent.
+- */
+-#define SETUP_RETL
+-#define RETL_INSN clr %o0
+-
+ /* Both these macros have to start with exactly the same insn */
+ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldd [%src + (offset) + 0x00], %t0; \
+@@ -154,7 +146,7 @@ FUNC(__memmove)
+ #endif
+ FUNC(memmove)
+ cmp %o0, %o1
+- SETUP_RETL
++ mov %o0, %g7
+ bleu 9f
+ sub %o0, %o1, %o4
+
+@@ -178,7 +170,7 @@ FUNC(memmove)
+ sub %o0, 1, %o0
+
+ retl
+- RETL_INSN
++ mov %g7, %o0
+
+ /* NOTE: This code is executed just for the cases,
+ where %src (=%o1) & 3 is != 0.
+@@ -212,7 +204,7 @@ FUNC(memmove)
+ FUNC(memcpy) /* %o0=dst %o1=src %o2=len */
+
+ sub %o0, %o1, %o4
+- SETUP_RETL
++ mov %o0, %g7
+ 9:
+ andcc %o4, 3, %o5
+ 0:
+@@ -308,7 +300,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ stb %g2, [%o0]
+ 1:
+ retl
+- RETL_INSN
++ mov %g7, %o0
+
+ 82: /* ldd_std */
+ MOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+@@ -373,7 +365,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ stb %g2, [%o0]
+ 1:
+ retl
+- RETL_INSN
++ mov %g7, %o0
+
+ 86: /* non_aligned */
+ cmp %o2, 6
+@@ -498,7 +490,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ stb %g2, [%i0 + 4]
+ 1:
+ ret
+- restore %g0, %g0, %o0
++ restore %g7, %g0, %o0
+
+ 88: /* short_end */
+
+@@ -529,7 +521,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ stb %g2, [%o0]
+ 1:
+ retl
+- RETL_INSN
++ mov %g7, %o0
+
+ 90: /* short_aligned_end */
+ bne 88b
--- /dev/null
+From 5a1b90af1e95b9ac5339f8d356c0a15a2b92c0d8 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Wed, 19 Oct 2011 15:15:58 -0700
+Subject: sparc32: Remove non-kernel code from memcpy implementation.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 045b7de9ca0cf09f1adc3efa467f668b89238390 ]
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Tested-by: Kjetil Oftedal <oftedal@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/lib/memcpy.S | 607 ------------------------------------------------
+ 1 file changed, 2 insertions(+), 605 deletions(-)
+
+--- a/arch/sparc/lib/memcpy.S
++++ b/arch/sparc/lib/memcpy.S
+@@ -7,17 +7,12 @@
+ * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+-#ifdef __KERNEL__
+-
+-#define FUNC(x) \
++#define FUNC(x) \
+ .globl x; \
+ .type x,@function; \
+- .align 4; \
++ .align 4; \
+ x:
+
+-#undef FASTER_REVERSE
+-#undef FASTER_NONALIGNED
+-#define FASTER_ALIGNED
+
+ /* In kernel these functions don't return a value.
+ * One should use macros in asm/string.h for that purpose.
+@@ -26,21 +21,6 @@ x:
+ #define SETUP_RETL
+ #define RETL_INSN clr %o0
+
+-#else
+-
+-/* libc */
+-
+-#include "DEFS.h"
+-
+-#define FASTER_REVERSE
+-#define FASTER_NONALIGNED
+-#define FASTER_ALIGNED
+-
+-#define SETUP_RETL mov %o0, %g6
+-#define RETL_INSN mov %g6, %o0
+-
+-#endif
+-
+ /* Both these macros have to start with exactly the same insn */
+ #define MOVE_BIGCHUNK(src, dst, offset, t0, t1, t2, t3, t4, t5, t6, t7) \
+ ldd [%src + (offset) + 0x00], %t0; \
+@@ -164,30 +144,6 @@ x:
+ .text
+ .align 4
+
+-#ifdef FASTER_REVERSE
+-
+-70: /* rdword_align */
+-
+- andcc %o1, 1, %g0
+- be 4f
+- andcc %o1, 2, %g0
+-
+- ldub [%o1 - 1], %g2
+- sub %o1, 1, %o1
+- stb %g2, [%o0 - 1]
+- sub %o2, 1, %o2
+- be 3f
+- sub %o0, 1, %o0
+-4:
+- lduh [%o1 - 2], %g2
+- sub %o1, 2, %o1
+- sth %g2, [%o0 - 2]
+- sub %o2, 2, %o2
+- b 3f
+- sub %o0, 2, %o0
+-
+-#endif /* FASTER_REVERSE */
+-
+ 0:
+ retl
+ nop ! Only bcopy returns here and it retuns void...
+@@ -207,8 +163,6 @@ FUNC(memmove)
+ bleu 0f
+ andcc %o4, 3, %o5
+
+-#ifndef FASTER_REVERSE
+-
+ add %o1, %o2, %o1
+ add %o0, %o2, %o0
+ sub %o1, 1, %o1
+@@ -226,294 +180,6 @@ FUNC(memmove)
+ retl
+ RETL_INSN
+
+-#else /* FASTER_REVERSE */
+-
+- add %o1, %o2, %o1
+- add %o0, %o2, %o0
+- bne 77f
+- cmp %o2, 15
+- bleu 91f
+- andcc %o1, 3, %g0
+- bne 70b
+-3:
+- andcc %o1, 4, %g0
+-
+- be 2f
+- mov %o2, %g1
+-
+- ld [%o1 - 4], %o4
+- sub %g1, 4, %g1
+- st %o4, [%o0 - 4]
+- sub %o1, 4, %o1
+- sub %o0, 4, %o0
+-2:
+- andcc %g1, 0xffffff80, %g7
+- be 3f
+- andcc %o0, 4, %g0
+-
+- be 74f + 4
+-5:
+- RMOVE_BIGCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+- subcc %g7, 128, %g7
+- sub %o1, 128, %o1
+- bne 5b
+- sub %o0, 128, %o0
+-3:
+- andcc %g1, 0x70, %g7
+- be 72f
+- andcc %g1, 8, %g0
+-
+- sethi %hi(72f), %o5
+- srl %g7, 1, %o4
+- add %g7, %o4, %o4
+- sub %o1, %g7, %o1
+- sub %o5, %o4, %o5
+- jmpl %o5 + %lo(72f), %g0
+- sub %o0, %g7, %o0
+-
+-71: /* rmemcpy_table */
+- RMOVE_LASTCHUNK(o1, o0, 0x60, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x50, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x40, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x30, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x20, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x10, g2, g3, g4, g5)
+- RMOVE_LASTCHUNK(o1, o0, 0x00, g2, g3, g4, g5)
+-
+-72: /* rmemcpy_table_end */
+-
+- be 73f
+- andcc %g1, 4, %g0
+-
+- ldd [%o1 - 0x08], %g2
+- sub %o0, 8, %o0
+- sub %o1, 8, %o1
+- st %g2, [%o0]
+- st %g3, [%o0 + 0x04]
+-
+-73: /* rmemcpy_last7 */
+-
+- be 1f
+- andcc %g1, 2, %g0
+-
+- ld [%o1 - 4], %g2
+- sub %o1, 4, %o1
+- st %g2, [%o0 - 4]
+- sub %o0, 4, %o0
+-1:
+- be 1f
+- andcc %g1, 1, %g0
+-
+- lduh [%o1 - 2], %g2
+- sub %o1, 2, %o1
+- sth %g2, [%o0 - 2]
+- sub %o0, 2, %o0
+-1:
+- be 1f
+- nop
+-
+- ldub [%o1 - 1], %g2
+- stb %g2, [%o0 - 1]
+-1:
+- retl
+- RETL_INSN
+-
+-74: /* rldd_std */
+- RMOVE_BIGALIGNCHUNK(o1, o0, 0x00, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+- RMOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+- subcc %g7, 128, %g7
+- sub %o1, 128, %o1
+- bne 74b
+- sub %o0, 128, %o0
+-
+- andcc %g1, 0x70, %g7
+- be 72b
+- andcc %g1, 8, %g0
+-
+- sethi %hi(72b), %o5
+- srl %g7, 1, %o4
+- add %g7, %o4, %o4
+- sub %o1, %g7, %o1
+- sub %o5, %o4, %o5
+- jmpl %o5 + %lo(72b), %g0
+- sub %o0, %g7, %o0
+-
+-75: /* rshort_end */
+-
+- and %o2, 0xe, %o3
+-2:
+- sethi %hi(76f), %o5
+- sll %o3, 3, %o4
+- sub %o0, %o3, %o0
+- sub %o5, %o4, %o5
+- sub %o1, %o3, %o1
+- jmpl %o5 + %lo(76f), %g0
+- andcc %o2, 1, %g0
+-
+- RMOVE_SHORTCHUNK(o1, o0, 0x0c, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x0a, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x08, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x06, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x04, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x02, g2, g3)
+- RMOVE_SHORTCHUNK(o1, o0, 0x00, g2, g3)
+-
+-76: /* rshort_table_end */
+-
+- be 1f
+- nop
+- ldub [%o1 - 1], %g2
+- stb %g2, [%o0 - 1]
+-1:
+- retl
+- RETL_INSN
+-
+-91: /* rshort_aligned_end */
+-
+- bne 75b
+- andcc %o2, 8, %g0
+-
+- be 1f
+- andcc %o2, 4, %g0
+-
+- ld [%o1 - 0x08], %g2
+- ld [%o1 - 0x04], %g3
+- sub %o1, 8, %o1
+- st %g2, [%o0 - 0x08]
+- st %g3, [%o0 - 0x04]
+- sub %o0, 8, %o0
+-1:
+- b 73b
+- mov %o2, %g1
+-
+-77: /* rnon_aligned */
+- cmp %o2, 15
+- bleu 75b
+- andcc %o0, 3, %g0
+- be 64f
+- andcc %o0, 1, %g0
+- be 63f
+- andcc %o0, 2, %g0
+- ldub [%o1 - 1], %g5
+- sub %o1, 1, %o1
+- stb %g5, [%o0 - 1]
+- sub %o0, 1, %o0
+- be 64f
+- sub %o2, 1, %o2
+-63:
+- ldub [%o1 - 1], %g5
+- sub %o1, 2, %o1
+- stb %g5, [%o0 - 1]
+- sub %o0, 2, %o0
+- ldub [%o1], %g5
+- sub %o2, 2, %o2
+- stb %g5, [%o0]
+-64:
+- and %o1, 3, %g2
+- and %o1, -4, %o1
+- and %o2, 0xc, %g3
+- add %o1, 4, %o1
+- cmp %g3, 4
+- sll %g2, 3, %g4
+- mov 32, %g2
+- be 4f
+- sub %g2, %g4, %g7
+-
+- blu 3f
+- cmp %g3, 8
+-
+- be 2f
+- srl %o2, 2, %g3
+-
+- ld [%o1 - 4], %o3
+- add %o0, -8, %o0
+- ld [%o1 - 8], %o4
+- add %o1, -16, %o1
+- b 7f
+- add %g3, 1, %g3
+-2:
+- ld [%o1 - 4], %o4
+- add %o0, -4, %o0
+- ld [%o1 - 8], %g1
+- add %o1, -12, %o1
+- b 8f
+- add %g3, 2, %g3
+-3:
+- ld [%o1 - 4], %o5
+- add %o0, -12, %o0
+- ld [%o1 - 8], %o3
+- add %o1, -20, %o1
+- b 6f
+- srl %o2, 2, %g3
+-4:
+- ld [%o1 - 4], %g1
+- srl %o2, 2, %g3
+- ld [%o1 - 8], %o5
+- add %o1, -24, %o1
+- add %o0, -16, %o0
+- add %g3, -1, %g3
+-
+- ld [%o1 + 12], %o3
+-5:
+- sll %o5, %g4, %g2
+- srl %g1, %g7, %g5
+- or %g2, %g5, %g2
+- st %g2, [%o0 + 12]
+-6:
+- ld [%o1 + 8], %o4
+- sll %o3, %g4, %g2
+- srl %o5, %g7, %g5
+- or %g2, %g5, %g2
+- st %g2, [%o0 + 8]
+-7:
+- ld [%o1 + 4], %g1
+- sll %o4, %g4, %g2
+- srl %o3, %g7, %g5
+- or %g2, %g5, %g2
+- st %g2, [%o0 + 4]
+-8:
+- ld [%o1], %o5
+- sll %g1, %g4, %g2
+- srl %o4, %g7, %g5
+- addcc %g3, -4, %g3
+- or %g2, %g5, %g2
+- add %o1, -16, %o1
+- st %g2, [%o0]
+- add %o0, -16, %o0
+- bne,a 5b
+- ld [%o1 + 12], %o3
+- sll %o5, %g4, %g2
+- srl %g1, %g7, %g5
+- srl %g4, 3, %g3
+- or %g2, %g5, %g2
+- add %o1, %g3, %o1
+- andcc %o2, 2, %g0
+- st %g2, [%o0 + 12]
+- be 1f
+- andcc %o2, 1, %g0
+-
+- ldub [%o1 + 15], %g5
+- add %o1, -2, %o1
+- stb %g5, [%o0 + 11]
+- add %o0, -2, %o0
+- ldub [%o1 + 16], %g5
+- stb %g5, [%o0 + 12]
+-1:
+- be 1f
+- nop
+- ldub [%o1 + 15], %g5
+- stb %g5, [%o0 + 11]
+-1:
+- retl
+- RETL_INSN
+-
+-#endif /* FASTER_REVERSE */
+-
+ /* NOTE: This code is executed just for the cases,
+ where %src (=%o1) & 3 is != 0.
+ We need to align it to 4. So, for (%src & 3)
+@@ -653,22 +319,6 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ bne 82b
+ add %o0, 128, %o0
+
+-#ifndef FASTER_ALIGNED
+-
+- andcc %g1, 0x70, %g7
+- be 80b
+- andcc %g1, 8, %g0
+-
+- sethi %hi(80b), %o5
+- srl %g7, 1, %o4
+- add %g7, %o4, %o4
+- add %o1, %g7, %o1
+- sub %o5, %o4, %o5
+- jmpl %o5 + %lo(80b), %g0
+- add %o0, %g7, %o0
+-
+-#else /* FASTER_ALIGNED */
+-
+ andcc %g1, 0x70, %g7
+ be 84f
+ andcc %g1, 8, %g0
+@@ -723,19 +373,9 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ retl
+ RETL_INSN
+
+-#endif /* FASTER_ALIGNED */
+-
+ 86: /* non_aligned */
+ cmp %o2, 6
+ bleu 88f
+-
+-#ifdef FASTER_NONALIGNED
+-
+- cmp %o2, 256
+- bcc 87f
+-
+-#endif /* FASTER_NONALIGNED */
+-
+ andcc %o0, 3, %g0
+ be 61f
+ andcc %o0, 1, %g0
+@@ -855,249 +495,6 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ retl
+ RETL_INSN
+
+-#ifdef FASTER_NONALIGNED
+-
+-87: /* faster_nonaligned */
+-
+- andcc %o1, 3, %g0
+- be 3f
+- andcc %o1, 1, %g0
+-
+- be 4f
+- andcc %o1, 2, %g0
+-
+- ldub [%o1], %g2
+- add %o1, 1, %o1
+- stb %g2, [%o0]
+- sub %o2, 1, %o2
+- bne 3f
+- add %o0, 1, %o0
+-4:
+- lduh [%o1], %g2
+- add %o1, 2, %o1
+- srl %g2, 8, %g3
+- sub %o2, 2, %o2
+- stb %g3, [%o0]
+- add %o0, 2, %o0
+- stb %g2, [%o0 - 1]
+-3:
+- andcc %o1, 4, %g0
+-
+- bne 2f
+- cmp %o5, 1
+-
+- ld [%o1], %o4
+- srl %o4, 24, %g2
+- stb %g2, [%o0]
+- srl %o4, 16, %g3
+- stb %g3, [%o0 + 1]
+- srl %o4, 8, %g2
+- stb %g2, [%o0 + 2]
+- sub %o2, 4, %o2
+- stb %o4, [%o0 + 3]
+- add %o1, 4, %o1
+- add %o0, 4, %o0
+-2:
+- be 33f
+- cmp %o5, 2
+- be 32f
+- sub %o2, 4, %o2
+-31:
+- ld [%o1], %g2
+- add %o1, 4, %o1
+- srl %g2, 24, %g3
+- and %o0, 7, %g5
+- stb %g3, [%o0]
+- cmp %g5, 7
+- sll %g2, 8, %g1
+- add %o0, 4, %o0
+- be 41f
+- and %o2, 0xffffffc0, %o3
+- ld [%o0 - 7], %o4
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 4b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 16, %g2
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 16, %g2
+-1:
+- st %o4, [%o0 - 7]
+- sth %g2, [%o0 - 3]
+- srl %g1, 8, %g4
+- b 88f
+- stb %g4, [%o0 - 1]
+-32:
+- ld [%o1], %g2
+- add %o1, 4, %o1
+- srl %g2, 16, %g3
+- and %o0, 7, %g5
+- sth %g3, [%o0]
+- cmp %g5, 6
+- sll %g2, 16, %g1
+- add %o0, 4, %o0
+- be 42f
+- and %o2, 0xffffffc0, %o3
+- ld [%o0 - 6], %o4
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 4b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 16, %g2
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 16, %g2
+-1:
+- st %o4, [%o0 - 6]
+- b 88f
+- sth %g2, [%o0 - 2]
+-33:
+- ld [%o1], %g2
+- sub %o2, 4, %o2
+- srl %g2, 24, %g3
+- and %o0, 7, %g5
+- stb %g3, [%o0]
+- cmp %g5, 5
+- srl %g2, 8, %g4
+- sll %g2, 24, %g1
+- sth %g4, [%o0 + 1]
+- add %o1, 4, %o1
+- be 43f
+- and %o2, 0xffffffc0, %o3
+-
+- ld [%o0 - 1], %o4
+- add %o0, 4, %o0
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+- SMOVE_CHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+- SMOVE_CHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+- SMOVE_CHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 4b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 24, %g2
+-4:
+- SMOVE_CHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, -1)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 24, %g2
+-1:
+- st %o4, [%o0 - 5]
+- b 88f
+- stb %g2, [%o0 - 1]
+-41:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 41b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 16, %g2
+-4:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 8, 24, -3)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 16, %g2
+-1:
+- sth %g2, [%o0 - 3]
+- srl %g1, 8, %g4
+- b 88f
+- stb %g4, [%o0 - 1]
+-43:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 43b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 24, %g2
+-4:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 24, 8, 3)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 24, %g2
+-1:
+- stb %g2, [%o0 + 3]
+- b 88f
+- add %o0, 4, %o0
+-42:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x10, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x20, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- SMOVE_ALIGNCHUNK(o1, o0, 0x30, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- subcc %o3, 64, %o3
+- add %o1, 64, %o1
+- bne 42b
+- add %o0, 64, %o0
+-
+- andcc %o2, 0x30, %o3
+- be,a 1f
+- srl %g1, 16, %g2
+-4:
+- SMOVE_ALIGNCHUNK(o1, o0, 0x00, g2, g3, g4, g5, o4, o5, g7, g1, 16, 16, -2)
+- subcc %o3, 16, %o3
+- add %o1, 16, %o1
+- bne 4b
+- add %o0, 16, %o0
+-
+- srl %g1, 16, %g2
+-1:
+- sth %g2, [%o0 - 2]
+-
+- /* Fall through */
+-
+-#endif /* FASTER_NONALIGNED */
+-
+ 88: /* short_end */
+
+ and %o2, 0xe, %o3
--- /dev/null
+From 0a7316055e710cf551484615c0b1887e156ed972 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Wed, 19 Oct 2011 15:30:14 -0700
+Subject: sparc32: Remove uses of %g7 in memcpy implementation.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 21f74d361dfd6a7d0e47574e315f780d8172084a ]
+
+This is setting things up so that we can correct the return
+value, so that it properly returns the original destination
+buffer pointer.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Tested-by: Kjetil Oftedal <oftedal@gmail.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/lib/memcpy.S | 177 ++++++++++++++++++++++++------------------------
+ 1 file changed, 91 insertions(+), 86 deletions(-)
+
+--- a/arch/sparc/lib/memcpy.S
++++ b/arch/sparc/lib/memcpy.S
+@@ -235,7 +235,7 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ add %o1, 4, %o1
+ add %o0, 4, %o0
+ 2:
+- andcc %g1, 0xffffff80, %g7
++ andcc %g1, 0xffffff80, %g0
+ be 3f
+ andcc %o0, 4, %g0
+
+@@ -245,22 +245,23 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ MOVE_BIGCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+ MOVE_BIGCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+ MOVE_BIGCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+- subcc %g7, 128, %g7
++ sub %g1, 128, %g1
+ add %o1, 128, %o1
+- bne 5b
++ cmp %g1, 128
++ bge 5b
+ add %o0, 128, %o0
+ 3:
+- andcc %g1, 0x70, %g7
++ andcc %g1, 0x70, %g4
+ be 80f
+ andcc %g1, 8, %g0
+
+ sethi %hi(80f), %o5
+- srl %g7, 1, %o4
+- add %g7, %o4, %o4
+- add %o1, %g7, %o1
++ srl %g4, 1, %o4
++ add %g4, %o4, %o4
++ add %o1, %g4, %o1
+ sub %o5, %o4, %o5
+ jmpl %o5 + %lo(80f), %g0
+- add %o0, %g7, %o0
++ add %o0, %g4, %o0
+
+ 79: /* memcpy_table */
+
+@@ -314,20 +315,21 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ MOVE_BIGALIGNCHUNK(o1, o0, 0x20, o2, o3, o4, o5, g2, g3, g4, g5)
+ MOVE_BIGALIGNCHUNK(o1, o0, 0x40, o2, o3, o4, o5, g2, g3, g4, g5)
+ MOVE_BIGALIGNCHUNK(o1, o0, 0x60, o2, o3, o4, o5, g2, g3, g4, g5)
+- subcc %g7, 128, %g7
++ subcc %g1, 128, %g1
+ add %o1, 128, %o1
+- bne 82b
++ cmp %g1, 128
++ bge 82b
+ add %o0, 128, %o0
+
+- andcc %g1, 0x70, %g7
++ andcc %g1, 0x70, %g4
+ be 84f
+ andcc %g1, 8, %g0
+
+ sethi %hi(84f), %o5
+- add %o1, %g7, %o1
+- sub %o5, %g7, %o5
++ add %o1, %g4, %o1
++ sub %o5, %g4, %o5
+ jmpl %o5 + %lo(84f), %g0
+- add %o0, %g7, %o0
++ add %o0, %g4, %o0
+
+ 83: /* amemcpy_table */
+
+@@ -376,124 +378,127 @@ FUNC(memcpy) /* %o0=dst %o1=src %o2=len
+ 86: /* non_aligned */
+ cmp %o2, 6
+ bleu 88f
+- andcc %o0, 3, %g0
++ nop
++
++ save %sp, -96, %sp
++ andcc %i0, 3, %g0
+ be 61f
+- andcc %o0, 1, %g0
++ andcc %i0, 1, %g0
+ be 60f
+- andcc %o0, 2, %g0
++ andcc %i0, 2, %g0
+
+- ldub [%o1], %g5
+- add %o1, 1, %o1
+- stb %g5, [%o0]
+- sub %o2, 1, %o2
++ ldub [%i1], %g5
++ add %i1, 1, %i1
++ stb %g5, [%i0]
++ sub %i2, 1, %i2
+ bne 61f
+- add %o0, 1, %o0
++ add %i0, 1, %i0
+ 60:
+- ldub [%o1], %g3
+- add %o1, 2, %o1
+- stb %g3, [%o0]
+- sub %o2, 2, %o2
+- ldub [%o1 - 1], %g3
+- add %o0, 2, %o0
+- stb %g3, [%o0 - 1]
++ ldub [%i1], %g3
++ add %i1, 2, %i1
++ stb %g3, [%i0]
++ sub %i2, 2, %i2
++ ldub [%i1 - 1], %g3
++ add %i0, 2, %i0
++ stb %g3, [%i0 - 1]
+ 61:
+- and %o1, 3, %g2
+- and %o2, 0xc, %g3
+- and %o1, -4, %o1
++ and %i1, 3, %g2
++ and %i2, 0xc, %g3
++ and %i1, -4, %i1
+ cmp %g3, 4
+ sll %g2, 3, %g4
+ mov 32, %g2
+ be 4f
+- sub %g2, %g4, %g7
++ sub %g2, %g4, %l0
+
+ blu 3f
+ cmp %g3, 0x8
+
+ be 2f
+- srl %o2, 2, %g3
++ srl %i2, 2, %g3
+
+- ld [%o1], %o3
+- add %o0, -8, %o0
+- ld [%o1 + 4], %o4
++ ld [%i1], %i3
++ add %i0, -8, %i0
++ ld [%i1 + 4], %i4
+ b 8f
+ add %g3, 1, %g3
+ 2:
+- ld [%o1], %o4
+- add %o0, -12, %o0
+- ld [%o1 + 4], %o5
++ ld [%i1], %i4
++ add %i0, -12, %i0
++ ld [%i1 + 4], %i5
+ add %g3, 2, %g3
+ b 9f
+- add %o1, -4, %o1
++ add %i1, -4, %i1
+ 3:
+- ld [%o1], %g1
+- add %o0, -4, %o0
+- ld [%o1 + 4], %o3
+- srl %o2, 2, %g3
++ ld [%i1], %g1
++ add %i0, -4, %i0
++ ld [%i1 + 4], %i3
++ srl %i2, 2, %g3
+ b 7f
+- add %o1, 4, %o1
++ add %i1, 4, %i1
+ 4:
+- ld [%o1], %o5
+- cmp %o2, 7
+- ld [%o1 + 4], %g1
+- srl %o2, 2, %g3
++ ld [%i1], %i5
++ cmp %i2, 7
++ ld [%i1 + 4], %g1
++ srl %i2, 2, %g3
+ bleu 10f
+- add %o1, 8, %o1
++ add %i1, 8, %i1
+
+- ld [%o1], %o3
++ ld [%i1], %i3
+ add %g3, -1, %g3
+ 5:
+- sll %o5, %g4, %g2
+- srl %g1, %g7, %g5
++ sll %i5, %g4, %g2
++ srl %g1, %l0, %g5
+ or %g2, %g5, %g2
+- st %g2, [%o0]
++ st %g2, [%i0]
+ 7:
+- ld [%o1 + 4], %o4
++ ld [%i1 + 4], %i4
+ sll %g1, %g4, %g2
+- srl %o3, %g7, %g5
++ srl %i3, %l0, %g5
+ or %g2, %g5, %g2
+- st %g2, [%o0 + 4]
++ st %g2, [%i0 + 4]
+ 8:
+- ld [%o1 + 8], %o5
+- sll %o3, %g4, %g2
+- srl %o4, %g7, %g5
++ ld [%i1 + 8], %i5
++ sll %i3, %g4, %g2
++ srl %i4, %l0, %g5
+ or %g2, %g5, %g2
+- st %g2, [%o0 + 8]
++ st %g2, [%i0 + 8]
+ 9:
+- ld [%o1 + 12], %g1
+- sll %o4, %g4, %g2
+- srl %o5, %g7, %g5
++ ld [%i1 + 12], %g1
++ sll %i4, %g4, %g2
++ srl %i5, %l0, %g5
+ addcc %g3, -4, %g3
+ or %g2, %g5, %g2
+- add %o1, 16, %o1
+- st %g2, [%o0 + 12]
+- add %o0, 16, %o0
++ add %i1, 16, %i1
++ st %g2, [%i0 + 12]
++ add %i0, 16, %i0
+ bne,a 5b
+- ld [%o1], %o3
++ ld [%i1], %i3
+ 10:
+- sll %o5, %g4, %g2
+- srl %g1, %g7, %g5
+- srl %g7, 3, %g3
++ sll %i5, %g4, %g2
++ srl %g1, %l0, %g5
++ srl %l0, 3, %g3
+ or %g2, %g5, %g2
+- sub %o1, %g3, %o1
+- andcc %o2, 2, %g0
+- st %g2, [%o0]
++ sub %i1, %g3, %i1
++ andcc %i2, 2, %g0
++ st %g2, [%i0]
+ be 1f
+- andcc %o2, 1, %g0
++ andcc %i2, 1, %g0
+
+- ldub [%o1], %g2
+- add %o1, 2, %o1
+- stb %g2, [%o0 + 4]
+- add %o0, 2, %o0
+- ldub [%o1 - 1], %g2
+- stb %g2, [%o0 + 3]
++ ldub [%i1], %g2
++ add %i1, 2, %i1
++ stb %g2, [%i0 + 4]
++ add %i0, 2, %i0
++ ldub [%i1 - 1], %g2
++ stb %g2, [%i0 + 3]
+ 1:
+ be 1f
+ nop
+- ldub [%o1], %g2
+- stb %g2, [%o0 + 4]
++ ldub [%i1], %g2
++ stb %g2, [%i0 + 4]
+ 1:
+- retl
+- RETL_INSN
++ ret
++ restore %g0, %g0, %o0
+
+ 88: /* short_end */
+
--- /dev/null
+From 612837c3502f6d1dd2d75b27778c6b8597ac4afc Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Mon, 31 Oct 2011 01:05:49 -0700
+Subject: sparc64: Fix masking and shifting in VIS fpcmp emulation.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 2e8ecdc008a16b9a6c4b9628bb64d0d1c05f9f92 ]
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/kernel/visemul.c | 32 ++++++++++++++++----------------
+ 1 file changed, 16 insertions(+), 16 deletions(-)
+
+--- a/arch/sparc/kernel/visemul.c
++++ b/arch/sparc/kernel/visemul.c
+@@ -713,17 +713,17 @@ static void pcmp(struct pt_regs *regs, u
+ s16 b = (rs2 >> (i * 16)) & 0xffff;
+
+ if (a > b)
+- rd_val |= 1 << i;
++ rd_val |= 8 >> i;
+ }
+ break;
+
+ case FCMPGT32_OPF:
+ for (i = 0; i < 2; i++) {
+- s32 a = (rs1 >> (i * 32)) & 0xffff;
+- s32 b = (rs2 >> (i * 32)) & 0xffff;
++ s32 a = (rs1 >> (i * 32)) & 0xffffffff;
++ s32 b = (rs2 >> (i * 32)) & 0xffffffff;
+
+ if (a > b)
+- rd_val |= 1 << i;
++ rd_val |= 2 >> i;
+ }
+ break;
+
+@@ -733,17 +733,17 @@ static void pcmp(struct pt_regs *regs, u
+ s16 b = (rs2 >> (i * 16)) & 0xffff;
+
+ if (a <= b)
+- rd_val |= 1 << i;
++ rd_val |= 8 >> i;
+ }
+ break;
+
+ case FCMPLE32_OPF:
+ for (i = 0; i < 2; i++) {
+- s32 a = (rs1 >> (i * 32)) & 0xffff;
+- s32 b = (rs2 >> (i * 32)) & 0xffff;
++ s32 a = (rs1 >> (i * 32)) & 0xffffffff;
++ s32 b = (rs2 >> (i * 32)) & 0xffffffff;
+
+ if (a <= b)
+- rd_val |= 1 << i;
++ rd_val |= 2 >> i;
+ }
+ break;
+
+@@ -753,17 +753,17 @@ static void pcmp(struct pt_regs *regs, u
+ s16 b = (rs2 >> (i * 16)) & 0xffff;
+
+ if (a != b)
+- rd_val |= 1 << i;
++ rd_val |= 8 >> i;
+ }
+ break;
+
+ case FCMPNE32_OPF:
+ for (i = 0; i < 2; i++) {
+- s32 a = (rs1 >> (i * 32)) & 0xffff;
+- s32 b = (rs2 >> (i * 32)) & 0xffff;
++ s32 a = (rs1 >> (i * 32)) & 0xffffffff;
++ s32 b = (rs2 >> (i * 32)) & 0xffffffff;
+
+ if (a != b)
+- rd_val |= 1 << i;
++ rd_val |= 2 >> i;
+ }
+ break;
+
+@@ -773,17 +773,17 @@ static void pcmp(struct pt_regs *regs, u
+ s16 b = (rs2 >> (i * 16)) & 0xffff;
+
+ if (a == b)
+- rd_val |= 1 << i;
++ rd_val |= 8 >> i;
+ }
+ break;
+
+ case FCMPEQ32_OPF:
+ for (i = 0; i < 2; i++) {
+- s32 a = (rs1 >> (i * 32)) & 0xffff;
+- s32 b = (rs2 >> (i * 32)) & 0xffff;
++ s32 a = (rs1 >> (i * 32)) & 0xffffffff;
++ s32 b = (rs2 >> (i * 32)) & 0xffffffff;
+
+ if (a == b)
+- rd_val |= 1 << i;
++ rd_val |= 2 >> i;
+ }
+ break;
+ }
--- /dev/null
+From f852e0fd1bb963a325ffe943a6ad9ef7d9bfb88b Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Thu, 22 Dec 2011 13:23:59 -0800
+Subject: sparc64: Fix MSIQ HV call ordering in pci_sun4v_msiq_build_irq().
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 7cc8583372a21d98a23b703ad96cab03180b5030 ]
+
+This silently was working for many years and stopped working on
+Niagara-T3 machines.
+
+We need to set the MSIQ to VALID before we can set it's state to IDLE.
+
+On Niagara-T3, setting the state to IDLE first was causing HV_EINVAL
+errors. The hypervisor documentation says, rather ambiguously, that
+the MSIQ must be "initialized" before one can set the state.
+
+I previously understood this to mean merely that a successful setconf()
+operation has been performed on the MSIQ, which we have done at this
+point. But it seems to also mean that it has been set VALID too.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/kernel/pci_sun4v.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/arch/sparc/kernel/pci_sun4v.c
++++ b/arch/sparc/kernel/pci_sun4v.c
+@@ -848,10 +848,10 @@ static int pci_sun4v_msiq_build_irq(stru
+ if (!irq)
+ return -ENOMEM;
+
+- if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
+- return -EINVAL;
+ if (pci_sun4v_msiq_setvalid(pbm->devhandle, msiqid, HV_MSIQ_VALID))
+ return -EINVAL;
++ if (pci_sun4v_msiq_setstate(pbm->devhandle, msiqid, HV_MSIQSTATE_IDLE))
++ return -EINVAL;
+
+ return irq;
+ }
--- /dev/null
+From 6f47e53783de70866c46a35cfc2d52bb3a8ae394 Mon Sep 17 00:00:00 2001
+From: "David S. Miller" <davem@davemloft.net>
+Date: Thu, 17 Nov 2011 22:44:58 -0800
+Subject: sparc64: Patch sun4v code sequences properly on module load.
+
+
+From: "David S. Miller" <davem@davemloft.net>
+
+[ Upstream commit 0b64120cceb86e93cb1bda0dc055f13016646907 ]
+
+Some of the sun4v code patching occurs in inline functions visible
+to, and usable by, modules.
+
+Therefore we have to patch them up during module load.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ arch/sparc/kernel/entry.h | 7 ++++++
+ arch/sparc/kernel/module.c | 27 ++++++++++++++++++++++++
+ arch/sparc/kernel/setup_64.c | 48 +++++++++++++++++++++++++------------------
+ 3 files changed, 63 insertions(+), 19 deletions(-)
+
+--- a/arch/sparc/kernel/entry.h
++++ b/arch/sparc/kernel/entry.h
+@@ -42,6 +42,9 @@ extern void fpsave(unsigned long *fpregs
+ extern void fpload(unsigned long *fpregs, unsigned long *fsr);
+
+ #else /* CONFIG_SPARC32 */
++
++#include <asm/trap_block.h>
++
+ struct popc_3insn_patch_entry {
+ unsigned int addr;
+ unsigned int insns[3];
+@@ -57,6 +60,10 @@ extern struct popc_6insn_patch_entry __p
+ __popc_6insn_patch_end;
+
+ extern void __init per_cpu_patch(void);
++extern void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *,
++ struct sun4v_1insn_patch_entry *);
++extern void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *,
++ struct sun4v_2insn_patch_entry *);
+ extern void __init sun4v_patch(void);
+ extern void __init boot_cpu_id_too_large(int cpu);
+ extern unsigned int dcache_parity_tl1_occurred;
+--- a/arch/sparc/kernel/module.c
++++ b/arch/sparc/kernel/module.c
+@@ -17,6 +17,8 @@
+ #include <asm/processor.h>
+ #include <asm/spitfire.h>
+
++#include "entry.h"
++
+ #ifdef CONFIG_SPARC64
+
+ #include <linux/jump_label.h>
+@@ -203,6 +205,29 @@ int apply_relocate_add(Elf_Shdr *sechdrs
+ }
+
+ #ifdef CONFIG_SPARC64
++static void do_patch_sections(const Elf_Ehdr *hdr,
++ const Elf_Shdr *sechdrs)
++{
++ const Elf_Shdr *s, *sun4v_1insn = NULL, *sun4v_2insn = NULL;
++ char *secstrings = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
++
++ for (s = sechdrs; s < sechdrs + hdr->e_shnum; s++) {
++ if (!strcmp(".sun4v_1insn_patch", secstrings + s->sh_name))
++ sun4v_1insn = s;
++ if (!strcmp(".sun4v_2insn_patch", secstrings + s->sh_name))
++ sun4v_2insn = s;
++ }
++
++ if (sun4v_1insn && tlb_type == hypervisor) {
++ void *p = (void *) sun4v_1insn->sh_addr;
++ sun4v_patch_1insn_range(p, p + sun4v_1insn->sh_size);
++ }
++ if (sun4v_2insn && tlb_type == hypervisor) {
++ void *p = (void *) sun4v_2insn->sh_addr;
++ sun4v_patch_2insn_range(p, p + sun4v_2insn->sh_size);
++ }
++}
++
+ int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+@@ -210,6 +235,8 @@ int module_finalize(const Elf_Ehdr *hdr,
+ /* make jump label nops */
+ jump_label_apply_nops(me);
+
++ do_patch_sections(hdr, sechdrs);
++
+ /* Cheetah's I-cache is fully coherent. */
+ if (tlb_type == spitfire) {
+ unsigned long va;
+--- a/arch/sparc/kernel/setup_64.c
++++ b/arch/sparc/kernel/setup_64.c
+@@ -234,40 +234,50 @@ void __init per_cpu_patch(void)
+ }
+ }
+
+-void __init sun4v_patch(void)
++void sun4v_patch_1insn_range(struct sun4v_1insn_patch_entry *start,
++ struct sun4v_1insn_patch_entry *end)
+ {
+- extern void sun4v_hvapi_init(void);
+- struct sun4v_1insn_patch_entry *p1;
+- struct sun4v_2insn_patch_entry *p2;
+-
+- if (tlb_type != hypervisor)
+- return;
++ while (start < end) {
++ unsigned long addr = start->addr;
+
+- p1 = &__sun4v_1insn_patch;
+- while (p1 < &__sun4v_1insn_patch_end) {
+- unsigned long addr = p1->addr;
+-
+- *(unsigned int *) (addr + 0) = p1->insn;
++ *(unsigned int *) (addr + 0) = start->insn;
+ wmb();
+ __asm__ __volatile__("flush %0" : : "r" (addr + 0));
+
+- p1++;
++ start++;
+ }
++}
+
+- p2 = &__sun4v_2insn_patch;
+- while (p2 < &__sun4v_2insn_patch_end) {
+- unsigned long addr = p2->addr;
++void sun4v_patch_2insn_range(struct sun4v_2insn_patch_entry *start,
++ struct sun4v_2insn_patch_entry *end)
++{
++ while (start < end) {
++ unsigned long addr = start->addr;
+
+- *(unsigned int *) (addr + 0) = p2->insns[0];
++ *(unsigned int *) (addr + 0) = start->insns[0];
+ wmb();
+ __asm__ __volatile__("flush %0" : : "r" (addr + 0));
+
+- *(unsigned int *) (addr + 4) = p2->insns[1];
++ *(unsigned int *) (addr + 4) = start->insns[1];
+ wmb();
+ __asm__ __volatile__("flush %0" : : "r" (addr + 4));
+
+- p2++;
++ start++;
+ }
++}
++
++void __init sun4v_patch(void)
++{
++ extern void sun4v_hvapi_init(void);
++
++ if (tlb_type != hypervisor)
++ return;
++
++ sun4v_patch_1insn_range(&__sun4v_1insn_patch,
++ &__sun4v_1insn_patch_end);
++
++ sun4v_patch_2insn_range(&__sun4v_2insn_patch,
++ &__sun4v_2insn_patch_end);
+
+ sun4v_hvapi_init();
+ }