]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
davem's patches queued for 2.6.20
authorChris Wright <chrisw@sous-sol.org>
Thu, 7 Jun 2007 18:37:11 +0000 (11:37 -0700)
committerChris Wright <chrisw@sous-sol.org>
Thu, 7 Jun 2007 18:37:11 +0000 (11:37 -0700)
16 files changed:
queue-2.6.20/fix-af_unix-oops.patch [new file with mode: 0644]
queue-2.6.20/icmp-fix-icmp_errors_use_inbound_ifaddr-sysctl.patch [new file with mode: 0644]
queue-2.6.20/ipsec-fix-panic-when-using-inter-address-familiy-ipsec-on-loopback.patch [new file with mode: 0644]
queue-2.6.20/ipv4-correct-rp_filter-help-text.patch [new file with mode: 0644]
queue-2.6.20/ipv6-route-no-longer-handle-0-specially.patch [new file with mode: 0644]
queue-2.6.20/net-fix-bmsr_100-half-full-2-defines-in-linux-mii.h.patch [new file with mode: 0644]
queue-2.6.20/net-fix-race-condition-about-network-device-name-allocation.patch [new file with mode: 0644]
queue-2.6.20/net-parse-ip-port-strings-correctly-in-in4_pton.patch [new file with mode: 0644]
queue-2.6.20/net-wrong-timeout-value-in-sk_wait_data-v2.patch [new file with mode: 0644]
queue-2.6.20/series
queue-2.6.20/sparc-linux-always-started-with-9600-8n1.patch [new file with mode: 0644]
queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch [new file with mode: 0644]
queue-2.6.20/sparc64-don-t-be-picky-about-virtual-dma-values-on-sun4v.patch [new file with mode: 0644]
queue-2.6.20/sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch [new file with mode: 0644]
queue-2.6.20/sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch [new file with mode: 0644]
queue-2.6.20/tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch [new file with mode: 0644]

diff --git a/queue-2.6.20/fix-af_unix-oops.patch b/queue-2.6.20/fix-af_unix-oops.patch
new file mode 100644 (file)
index 0000000..d522581
--- /dev/null
@@ -0,0 +1,482 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:28:45 2007
+Date: Wed, 06 Jun 2007 22:28:53 -0700 (PDT)
+Message-Id: <20070606.222853.10297477.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: Fix AF_UNIX OOPS
+
+This combines two upstream commits to fix an OOPS with
+AF_UNIX and SELINUX.
+
+basically, sk->sk_socket can become null because we access
+a peer socket without any locking, so it can be shut down and
+released in another thread.
+
+Commit: d410b81b4eef2e4409f9c38ef201253fbbcc7d94
+[AF_UNIX]: Make socket locking much less confusing.
+
+The unix_state_*() locking macros imply that there is some
+rwlock kind of thing going on, but the implementation is
+actually a spinlock which makes the code more confusing than
+it needs to be.
+
+So use plain unix_state_lock and unix_state_unlock.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+
+Commit: 19fec3e807a487415e77113cb9dbdaa2da739836
+[AF_UNIX]: Fix datagram connect race causing an OOPS.
+
+Based upon an excellent bug report and initial patch by
+Frederik Deweerdt.
+
+The UNIX datagram connect code blindly dereferences other->sk_socket
+via the call down to the security_unix_may_send() function.
+
+Without locking 'other' that pointer can go NULL via unix_release_sock()
+which does sock_orphan() which also marks the socket SOCK_DEAD.
+
+So we have to lock both 'sk' and 'other' yet avoid all kinds of
+potential deadlocks (connect to self is OK for datagram sockets and it
+is possible for two datagram sockets to perform a simultaneous connect
+to each other).  So what we do is have a "double lock" function similar
+to how we handle this situation in other areas of the kernel.  We take
+the lock of the socket pointer with the smallest address first in
+order to avoid ABBA style deadlocks.
+
+Once we have them both locked, we check to see if SOCK_DEAD is set
+for 'other' and if so, drop everything and retry the lookup.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ include/net/af_unix.h |    8 +--
+ net/unix/af_unix.c    |  127 +++++++++++++++++++++++++++++++-------------------
+ 2 files changed, 83 insertions(+), 52 deletions(-)
+
+--- linux-2.6.20.12.orig/include/net/af_unix.h
++++ linux-2.6.20.12/include/net/af_unix.h
+@@ -62,13 +62,11 @@ struct unix_skb_parms {
+ #define UNIXCREDS(skb)        (&UNIXCB((skb)).creds)
+ #define UNIXSID(skb)  (&UNIXCB((skb)).secid)
+-#define unix_state_rlock(s)   spin_lock(&unix_sk(s)->lock)
+-#define unix_state_runlock(s) spin_unlock(&unix_sk(s)->lock)
+-#define unix_state_wlock(s)   spin_lock(&unix_sk(s)->lock)
+-#define unix_state_wlock_nested(s) \
++#define unix_state_lock(s)    spin_lock(&unix_sk(s)->lock)
++#define unix_state_unlock(s)  spin_unlock(&unix_sk(s)->lock)
++#define unix_state_lock_nested(s) \
+                               spin_lock_nested(&unix_sk(s)->lock, \
+                               SINGLE_DEPTH_NESTING)
+-#define unix_state_wunlock(s) spin_unlock(&unix_sk(s)->lock)
+ #ifdef __KERNEL__
+ /* The AF_UNIX socket */
+--- linux-2.6.20.12.orig/net/unix/af_unix.c
++++ linux-2.6.20.12/net/unix/af_unix.c
+@@ -175,11 +175,11 @@ static struct sock *unix_peer_get(struct
+ {
+       struct sock *peer;
+-      unix_state_rlock(s);
++      unix_state_lock(s);
+       peer = unix_peer(s);
+       if (peer)
+               sock_hold(peer);
+-      unix_state_runlock(s);
++      unix_state_unlock(s);
+       return peer;
+ }
+@@ -370,7 +370,7 @@ static int unix_release_sock (struct soc
+       unix_remove_socket(sk);
+       /* Clear state */
+-      unix_state_wlock(sk);
++      unix_state_lock(sk);
+       sock_orphan(sk);
+       sk->sk_shutdown = SHUTDOWN_MASK;
+       dentry       = u->dentry;
+@@ -379,7 +379,7 @@ static int unix_release_sock (struct soc
+       u->mnt       = NULL;
+       state = sk->sk_state;
+       sk->sk_state = TCP_CLOSE;
+-      unix_state_wunlock(sk);
++      unix_state_unlock(sk);
+       wake_up_interruptible_all(&u->peer_wait);
+@@ -387,12 +387,12 @@ static int unix_release_sock (struct soc
+       if (skpair!=NULL) {
+               if (sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET) {
+-                      unix_state_wlock(skpair);
++                      unix_state_lock(skpair);
+                       /* No more writes */
+                       skpair->sk_shutdown = SHUTDOWN_MASK;
+                       if (!skb_queue_empty(&sk->sk_receive_queue) || embrion)
+                               skpair->sk_err = ECONNRESET;
+-                      unix_state_wunlock(skpair);
++                      unix_state_unlock(skpair);
+                       skpair->sk_state_change(skpair);
+                       read_lock(&skpair->sk_callback_lock);
+                       sk_wake_async(skpair,1,POLL_HUP);
+@@ -449,7 +449,7 @@ static int unix_listen(struct socket *so
+       err = -EINVAL;
+       if (!u->addr)
+               goto out;                       /* No listens on an unbound socket */
+-      unix_state_wlock(sk);
++      unix_state_lock(sk);
+       if (sk->sk_state != TCP_CLOSE && sk->sk_state != TCP_LISTEN)
+               goto out_unlock;
+       if (backlog > sk->sk_max_ack_backlog)
+@@ -463,7 +463,7 @@ static int unix_listen(struct socket *so
+       err = 0;
+ out_unlock:
+-      unix_state_wunlock(sk);
++      unix_state_unlock(sk);
+ out:
+       return err;
+ }
+@@ -859,6 +859,31 @@ out_mknod_parent:
+       goto out_up;
+ }
++static void unix_state_double_lock(struct sock *sk1, struct sock *sk2)
++{
++      if (unlikely(sk1 == sk2) || !sk2) {
++              unix_state_lock(sk1);
++              return;
++      }
++      if (sk1 < sk2) {
++              unix_state_lock(sk1);
++              unix_state_lock_nested(sk2);
++      } else {
++              unix_state_lock(sk2);
++              unix_state_lock_nested(sk1);
++      }
++}
++
++static void unix_state_double_unlock(struct sock *sk1, struct sock *sk2)
++{
++      if (unlikely(sk1 == sk2) || !sk2) {
++              unix_state_unlock(sk1);
++              return;
++      }
++      unix_state_unlock(sk1);
++      unix_state_unlock(sk2);
++}
++
+ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr,
+                             int alen, int flags)
+ {
+@@ -878,11 +903,19 @@ static int unix_dgram_connect(struct soc
+                   !unix_sk(sk)->addr && (err = unix_autobind(sock)) != 0)
+                       goto out;
++restart:
+               other=unix_find_other(sunaddr, alen, sock->type, hash, &err);
+               if (!other)
+                       goto out;
+-              unix_state_wlock(sk);
++              unix_state_double_lock(sk, other);
++
++              /* Apparently VFS overslept socket death. Retry. */
++              if (sock_flag(other, SOCK_DEAD)) {
++                      unix_state_double_unlock(sk, other);
++                      sock_put(other);
++                      goto restart;
++              }
+               err = -EPERM;
+               if (!unix_may_send(sk, other))
+@@ -897,7 +930,7 @@ static int unix_dgram_connect(struct soc
+                *      1003.1g breaking connected state with AF_UNSPEC
+                */
+               other = NULL;
+-              unix_state_wlock(sk);
++              unix_state_double_lock(sk, other);
+       }
+       /*
+@@ -906,19 +939,19 @@ static int unix_dgram_connect(struct soc
+       if (unix_peer(sk)) {
+               struct sock *old_peer = unix_peer(sk);
+               unix_peer(sk)=other;
+-              unix_state_wunlock(sk);
++              unix_state_double_unlock(sk, other);
+               if (other != old_peer)
+                       unix_dgram_disconnected(sk, old_peer);
+               sock_put(old_peer);
+       } else {
+               unix_peer(sk)=other;
+-              unix_state_wunlock(sk);
++              unix_state_double_unlock(sk, other);
+       }
+       return 0;
+ out_unlock:
+-      unix_state_wunlock(sk);
++      unix_state_double_unlock(sk, other);
+       sock_put(other);
+ out:
+       return err;
+@@ -937,7 +970,7 @@ static long unix_wait_for_peer(struct so
+               (skb_queue_len(&other->sk_receive_queue) >
+                other->sk_max_ack_backlog);
+-      unix_state_runlock(other);
++      unix_state_unlock(other);
+       if (sched)
+               timeo = schedule_timeout(timeo);
+@@ -995,11 +1028,11 @@ restart:
+               goto out;
+       /* Latch state of peer */
+-      unix_state_rlock(other);
++      unix_state_lock(other);
+       /* Apparently VFS overslept socket death. Retry. */
+       if (sock_flag(other, SOCK_DEAD)) {
+-              unix_state_runlock(other);
++              unix_state_unlock(other);
+               sock_put(other);
+               goto restart;
+       }
+@@ -1049,18 +1082,18 @@ restart:
+               goto out_unlock;
+       }
+-      unix_state_wlock_nested(sk);
++      unix_state_lock_nested(sk);
+       if (sk->sk_state != st) {
+-              unix_state_wunlock(sk);
+-              unix_state_runlock(other);
++              unix_state_unlock(sk);
++              unix_state_unlock(other);
+               sock_put(other);
+               goto restart;
+       }
+       err = security_unix_stream_connect(sock, other->sk_socket, newsk);
+       if (err) {
+-              unix_state_wunlock(sk);
++              unix_state_unlock(sk);
+               goto out_unlock;
+       }
+@@ -1097,7 +1130,7 @@ restart:
+       smp_mb__after_atomic_inc();     /* sock_hold() does an atomic_inc() */
+       unix_peer(sk)   = newsk;
+-      unix_state_wunlock(sk);
++      unix_state_unlock(sk);
+       /* take ten and and send info to listening sock */
+       spin_lock(&other->sk_receive_queue.lock);
+@@ -1106,14 +1139,14 @@ restart:
+        * is installed to listening socket. */
+       atomic_inc(&newu->inflight);
+       spin_unlock(&other->sk_receive_queue.lock);
+-      unix_state_runlock(other);
++      unix_state_unlock(other);
+       other->sk_data_ready(other, 0);
+       sock_put(other);
+       return 0;
+ out_unlock:
+       if (other)
+-              unix_state_runlock(other);
++              unix_state_unlock(other);
+ out:
+       if (skb)
+@@ -1179,10 +1212,10 @@ static int unix_accept(struct socket *so
+       wake_up_interruptible(&unix_sk(sk)->peer_wait);
+       /* attach accepted sock to socket */
+-      unix_state_wlock(tsk);
++      unix_state_lock(tsk);
+       newsock->state = SS_CONNECTED;
+       sock_graft(tsk, newsock);
+-      unix_state_wunlock(tsk);
++      unix_state_unlock(tsk);
+       return 0;
+ out:
+@@ -1209,7 +1242,7 @@ static int unix_getname(struct socket *s
+       }
+       u = unix_sk(sk);
+-      unix_state_rlock(sk);
++      unix_state_lock(sk);
+       if (!u->addr) {
+               sunaddr->sun_family = AF_UNIX;
+               sunaddr->sun_path[0] = 0;
+@@ -1220,7 +1253,7 @@ static int unix_getname(struct socket *s
+               *uaddr_len = addr->len;
+               memcpy(sunaddr, addr->name, *uaddr_len);
+       }
+-      unix_state_runlock(sk);
++      unix_state_unlock(sk);
+       sock_put(sk);
+ out:
+       return err;
+@@ -1338,7 +1371,7 @@ restart:
+                       goto out_free;
+       }
+-      unix_state_rlock(other);
++      unix_state_lock(other);
+       err = -EPERM;
+       if (!unix_may_send(sk, other))
+               goto out_unlock;
+@@ -1348,20 +1381,20 @@ restart:
+                *      Check with 1003.1g - what should
+                *      datagram error
+                */
+-              unix_state_runlock(other);
++              unix_state_unlock(other);
+               sock_put(other);
+               err = 0;
+-              unix_state_wlock(sk);
++              unix_state_lock(sk);
+               if (unix_peer(sk) == other) {
+                       unix_peer(sk)=NULL;
+-                      unix_state_wunlock(sk);
++                      unix_state_unlock(sk);
+                       unix_dgram_disconnected(sk, other);
+                       sock_put(other);
+                       err = -ECONNREFUSED;
+               } else {
+-                      unix_state_wunlock(sk);
++                      unix_state_unlock(sk);
+               }
+               other = NULL;
+@@ -1398,14 +1431,14 @@ restart:
+       }
+       skb_queue_tail(&other->sk_receive_queue, skb);
+-      unix_state_runlock(other);
++      unix_state_unlock(other);
+       other->sk_data_ready(other, len);
+       sock_put(other);
+       scm_destroy(siocb->scm);
+       return len;
+ out_unlock:
+-      unix_state_runlock(other);
++      unix_state_unlock(other);
+ out_free:
+       kfree_skb(skb);
+ out:
+@@ -1495,14 +1528,14 @@ static int unix_stream_sendmsg(struct ki
+                       goto out_err;
+               }
+-              unix_state_rlock(other);
++              unix_state_lock(other);
+               if (sock_flag(other, SOCK_DEAD) ||
+                   (other->sk_shutdown & RCV_SHUTDOWN))
+                       goto pipe_err_free;
+               skb_queue_tail(&other->sk_receive_queue, skb);
+-              unix_state_runlock(other);
++              unix_state_unlock(other);
+               other->sk_data_ready(other, size);
+               sent+=size;
+       }
+@@ -1513,7 +1546,7 @@ static int unix_stream_sendmsg(struct ki
+       return sent;
+ pipe_err_free:
+-      unix_state_runlock(other);
++      unix_state_unlock(other);
+       kfree_skb(skb);
+ pipe_err:
+       if (sent==0 && !(msg->msg_flags&MSG_NOSIGNAL))
+@@ -1642,7 +1675,7 @@ static long unix_stream_data_wait(struct
+ {
+       DEFINE_WAIT(wait);
+-      unix_state_rlock(sk);
++      unix_state_lock(sk);
+       for (;;) {
+               prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
+@@ -1655,14 +1688,14 @@ static long unix_stream_data_wait(struct
+                       break;
+               set_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+-              unix_state_runlock(sk);
++              unix_state_unlock(sk);
+               timeo = schedule_timeout(timeo);
+-              unix_state_rlock(sk);
++              unix_state_lock(sk);
+               clear_bit(SOCK_ASYNC_WAITDATA, &sk->sk_socket->flags);
+       }
+       finish_wait(sk->sk_sleep, &wait);
+-      unix_state_runlock(sk);
++      unix_state_unlock(sk);
+       return timeo;
+ }
+@@ -1817,12 +1850,12 @@ static int unix_shutdown(struct socket *
+       mode = (mode+1)&(RCV_SHUTDOWN|SEND_SHUTDOWN);
+       if (mode) {
+-              unix_state_wlock(sk);
++              unix_state_lock(sk);
+               sk->sk_shutdown |= mode;
+               other=unix_peer(sk);
+               if (other)
+                       sock_hold(other);
+-              unix_state_wunlock(sk);
++              unix_state_unlock(sk);
+               sk->sk_state_change(sk);
+               if (other &&
+@@ -1834,9 +1867,9 @@ static int unix_shutdown(struct socket *
+                               peer_mode |= SEND_SHUTDOWN;
+                       if (mode&SEND_SHUTDOWN)
+                               peer_mode |= RCV_SHUTDOWN;
+-                      unix_state_wlock(other);
++                      unix_state_lock(other);
+                       other->sk_shutdown |= peer_mode;
+-                      unix_state_wunlock(other);
++                      unix_state_unlock(other);
+                       other->sk_state_change(other);
+                       read_lock(&other->sk_callback_lock);
+                       if (peer_mode == SHUTDOWN_MASK)
+@@ -1974,7 +2007,7 @@ static int unix_seq_show(struct seq_file
+       else {
+               struct sock *s = v;
+               struct unix_sock *u = unix_sk(s);
+-              unix_state_rlock(s);
++              unix_state_lock(s);
+               seq_printf(seq, "%p: %08X %08X %08X %04X %02X %5lu",
+                       s,
+@@ -2002,7 +2035,7 @@ static int unix_seq_show(struct seq_file
+                       for ( ; i < len; i++)
+                               seq_putc(seq, u->addr->name->sun_path[i]);
+               }
+-              unix_state_runlock(s);
++              unix_state_unlock(s);
+               seq_putc(seq, '\n');
+       }
diff --git a/queue-2.6.20/icmp-fix-icmp_errors_use_inbound_ifaddr-sysctl.patch b/queue-2.6.20/icmp-fix-icmp_errors_use_inbound_ifaddr-sysctl.patch
new file mode 100644 (file)
index 0000000..c172c96
--- /dev/null
@@ -0,0 +1,44 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:38:00 2007
+Date: Wed, 06 Jun 2007 22:38:11 -0700 (PDT)
+Message-Id: <20070606.223811.34759359.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: ICMP: Fix icmp_errors_use_inbound_ifaddr sysctl
+
+Currently when icmp_errors_use_inbound_ifaddr is set and an ICMP error is
+sent after the packet passed through ip_output(), an address from the
+outgoing interface is chosen as ICMP source address since skb->dev doesn't
+point to the incoming interface anymore.
+
+Fix this by doing an interface lookup on rt->dst.iif and using that device.
+
+Signed-off-by: Patrick McHardy <kaber@trash.net>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/icmp.c |   12 +++++++++---
+ 1 file changed, 9 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/icmp.c
++++ linux-2.6.20.12/net/ipv4/icmp.c
+@@ -513,9 +513,15 @@ void icmp_send(struct sk_buff *skb_in, i
+       saddr = iph->daddr;
+       if (!(rt->rt_flags & RTCF_LOCAL)) {
+-              if (sysctl_icmp_errors_use_inbound_ifaddr)
+-                      saddr = inet_select_addr(skb_in->dev, 0, RT_SCOPE_LINK);
+-              else
++              struct net_device *dev = NULL;
++
++              if (rt->fl.iif && sysctl_icmp_errors_use_inbound_ifaddr)
++                      dev = dev_get_by_index(rt->fl.iif);
++
++              if (dev) {
++                      saddr = inet_select_addr(dev, 0, RT_SCOPE_LINK);
++                      dev_put(dev);
++              } else
+                       saddr = 0;
+       }
diff --git a/queue-2.6.20/ipsec-fix-panic-when-using-inter-address-familiy-ipsec-on-loopback.patch b/queue-2.6.20/ipsec-fix-panic-when-using-inter-address-familiy-ipsec-on-loopback.patch
new file mode 100644 (file)
index 0000000..8ecb038
--- /dev/null
@@ -0,0 +1,72 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:41:41 2007
+Date: Wed, 06 Jun 2007 22:41:52 -0700 (PDT)
+Message-Id: <20070606.224152.68156938.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPSEC: Fix panic when using inter address familiy IPsec on loopback.
+
+From: Kazunori MIYAZAWA <kazunori@miyazawa.org>
+
+Signed-off-by: Kazunori MIYAZAWA <kazunori@miyazawa.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/xfrm4_input.c       |    6 ++----
+ net/ipv4/xfrm4_mode_tunnel.c |    2 ++
+ net/ipv6/xfrm6_input.c       |    6 ++----
+ net/ipv6/xfrm6_mode_tunnel.c |    1 +
+ 4 files changed, 7 insertions(+), 8 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/xfrm4_input.c
++++ linux-2.6.20.12/net/ipv4/xfrm4_input.c
+@@ -136,10 +136,8 @@ int xfrm4_rcv_encap(struct sk_buff *skb,
+       nf_reset(skb);
+       if (decaps) {
+-              if (!(skb->dev->flags&IFF_LOOPBACK)) {
+-                      dst_release(skb->dst);
+-                      skb->dst = NULL;
+-              }
++              dst_release(skb->dst);
++              skb->dst = NULL;
+               netif_rx(skb);
+               return 0;
+       } else {
+--- linux-2.6.20.12.orig/net/ipv4/xfrm4_mode_tunnel.c
++++ linux-2.6.20.12/net/ipv4/xfrm4_mode_tunnel.c
+@@ -66,6 +66,8 @@ static int xfrm4_tunnel_output(struct xf
+       top_iph->daddr = x->id.daddr.a4;
+       top_iph->protocol = IPPROTO_IPIP;
++      skb->protocol = htons(ETH_P_IP);
++
+       memset(&(IPCB(skb)->opt), 0, sizeof(struct ip_options));
+       return 0;
+ }
+--- linux-2.6.20.12.orig/net/ipv6/xfrm6_input.c
++++ linux-2.6.20.12/net/ipv6/xfrm6_input.c
+@@ -103,10 +103,8 @@ int xfrm6_rcv_spi(struct sk_buff *skb, _
+       nf_reset(skb);
+       if (decaps) {
+-              if (!(skb->dev->flags&IFF_LOOPBACK)) {
+-                      dst_release(skb->dst);
+-                      skb->dst = NULL;
+-              }
++              dst_release(skb->dst);
++              skb->dst = NULL;
+               netif_rx(skb);
+               return -1;
+       } else {
+--- linux-2.6.20.12.orig/net/ipv6/xfrm6_mode_tunnel.c
++++ linux-2.6.20.12/net/ipv6/xfrm6_mode_tunnel.c
+@@ -65,6 +65,7 @@ static int xfrm6_tunnel_output(struct xf
+       top_iph->hop_limit = dst_metric(dst->child, RTAX_HOPLIMIT);
+       ipv6_addr_copy(&top_iph->saddr, (struct in6_addr *)&x->props.saddr);
+       ipv6_addr_copy(&top_iph->daddr, (struct in6_addr *)&x->id.daddr);
++      skb->protocol = htons(ETH_P_IPV6);
+       return 0;
+ }
diff --git a/queue-2.6.20/ipv4-correct-rp_filter-help-text.patch b/queue-2.6.20/ipv4-correct-rp_filter-help-text.patch
new file mode 100644 (file)
index 0000000..456e74b
--- /dev/null
@@ -0,0 +1,40 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:47:58 2007
+Date: Wed, 06 Jun 2007 22:48:09 -0700 (PDT)
+Message-Id: <20070606.224809.35355405.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPV4: Correct rp_filter help text.
+
+From: Dave Jones <davej@redhat.com>
+
+As mentioned in http://bugzilla.kernel.org/show_bug.cgi?id=5015
+The helptext implies that this is on by default.
+This may be true on some distros (Fedora/RHEL have it enabled
+in /etc/sysctl.conf), but the kernel defaults to it off.
+
+Signed-off-by: Dave Jones <davej@redhat.com>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv4/Kconfig |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/Kconfig
++++ linux-2.6.20.12/net/ipv4/Kconfig
+@@ -43,11 +43,11 @@ config IP_ADVANCED_ROUTER
+         asymmetric routing (packets from you to a host take a different path
+         than packets from that host to you) or if you operate a non-routing
+         host which has several IP addresses on different interfaces. To turn
+-        rp_filter off use:
++        rp_filter on use:
+-        echo 0 > /proc/sys/net/ipv4/conf/<device>/rp_filter
++        echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter
+         or
+-        echo 0 > /proc/sys/net/ipv4/conf/all/rp_filter
++        echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
+         If unsure, say N here.
diff --git a/queue-2.6.20/ipv6-route-no-longer-handle-0-specially.patch b/queue-2.6.20/ipv6-route-no-longer-handle-0-specially.patch
new file mode 100644 (file)
index 0000000..d50f98a
--- /dev/null
@@ -0,0 +1,40 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:42:46 2007
+Date: Wed, 06 Jun 2007 22:42:58 -0700 (PDT)
+Message-Id: <20070606.224258.27782785.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: IPV6 ROUTE: No longer handle ::/0 specially.
+
+From: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+
+We do not need to handle ::/0 routes specially any longer.
+This should fix BUG #8349.
+
+Signed-off-by: YOSHIFUJI Hideaki <yoshfuji@linux-ipv6.org>
+Acked-by: Yuji Sekiya <sekiya@wide.ad.jp>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/ipv6/ip6_fib.c |    8 --------
+ 1 file changed, 8 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv6/ip6_fib.c
++++ linux-2.6.20.12/net/ipv6/ip6_fib.c
+@@ -620,14 +620,6 @@ static int fib6_add_rt2node(struct fib6_
+       ins = &fn->leaf;
+-      if (fn->fn_flags&RTN_TL_ROOT &&
+-          fn->leaf == &ip6_null_entry &&
+-          !(rt->rt6i_flags & (RTF_DEFAULT | RTF_ADDRCONF)) ){
+-              fn->leaf = rt;
+-              rt->u.next = NULL;
+-              goto out;
+-      }
+-
+       for (iter = fn->leaf; iter; iter=iter->u.next) {
+               /*
+                *      Search for duplicates
diff --git a/queue-2.6.20/net-fix-bmsr_100-half-full-2-defines-in-linux-mii.h.patch b/queue-2.6.20/net-fix-bmsr_100-half-full-2-defines-in-linux-mii.h.patch
new file mode 100644 (file)
index 0000000..ea2949e
--- /dev/null
@@ -0,0 +1,30 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:44:02 2007
+Date: Wed, 06 Jun 2007 22:44:14 -0700 (PDT)
+Message-Id: <20070606.224414.77057904.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: Fix BMSR_100{HALF,FULL}2 defines in linux/mii.h
+
+Noticed by Matvejchikov Ilya.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ include/linux/mii.h |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-2.6.20.12.orig/include/linux/mii.h
++++ linux-2.6.20.12/include/linux/mii.h
+@@ -56,8 +56,8 @@
+ #define BMSR_ANEGCOMPLETE       0x0020  /* Auto-negotiation complete   */
+ #define BMSR_RESV               0x00c0  /* Unused...                   */
+ #define BMSR_ESTATEN          0x0100  /* Extended Status in R15 */
+-#define BMSR_100FULL2         0x0200  /* Can do 100BASE-T2 HDX */
+-#define BMSR_100HALF2         0x0400  /* Can do 100BASE-T2 FDX */
++#define BMSR_100HALF2           0x0200  /* Can do 100BASE-T2 HDX */
++#define BMSR_100FULL2           0x0400  /* Can do 100BASE-T2 FDX */
+ #define BMSR_10HALF             0x0800  /* Can do 10mbps, half-duplex  */
+ #define BMSR_10FULL             0x1000  /* Can do 10mbps, full-duplex  */
+ #define BMSR_100HALF            0x2000  /* Can do 100mbps, half-duplex */
diff --git a/queue-2.6.20/net-fix-race-condition-about-network-device-name-allocation.patch b/queue-2.6.20/net-fix-race-condition-about-network-device-name-allocation.patch
new file mode 100644 (file)
index 0000000..be08d05
--- /dev/null
@@ -0,0 +1,84 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:46:56 2007
+Date: Wed, 06 Jun 2007 22:47:07 -0700 (PDT)
+Message-Id: <20070606.224707.26532542.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: Fix race condition about network device name allocation.
+
+From: Stephen Hemminger <shemminger@linux-foundation.org>
+
+Kenji Kaneshige found this race between device removal and
+registration.  On unregister it is possible for the old device to
+exist, because sysfs file is still open.  A new device with 'eth%d'
+will select the same name, but sysfs kobject register will fial.
+
+The following changes the shutdown order slightly. It hold a removes
+the sysfs entries earlier (on unregister_netdevice), but holds a
+kobject reference.  Then when todo runs the actual last put free
+happens.
+
+Signed-off-by: Stephen Hemminger <shemminger@linux-foundation.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/dev.c       |   10 ++++++----
+ net/core/net-sysfs.c |    8 +++++++-
+ 2 files changed, 13 insertions(+), 5 deletions(-)
+
+--- linux-2.6.20.12.orig/net/core/dev.c
++++ linux-2.6.20.12/net/core/dev.c
+@@ -3138,7 +3138,6 @@ void netdev_run_todo(void)
+                       continue;
+               }
+-              netdev_unregister_sysfs(dev);
+               dev->reg_state = NETREG_UNREGISTERED;
+               netdev_wait_allrefs(dev);
+@@ -3149,11 +3148,11 @@ void netdev_run_todo(void)
+               BUG_TRAP(!dev->ip6_ptr);
+               BUG_TRAP(!dev->dn_ptr);
+-              /* It must be the very last action,
+-               * after this 'dev' may point to freed up memory.
+-               */
+               if (dev->destructor)
+                       dev->destructor(dev);
++
++              /* Free network device */
++              kobject_put(&dev->dev.kobj);
+       }
+ out:
+@@ -3310,6 +3309,9 @@ int unregister_netdevice(struct net_devi
+       /* Notifier chain MUST detach us from master device. */
+       BUG_TRAP(!dev->master);
++      /* Remove entries from sysfs */
++      netdev_unregister_sysfs(dev);
++
+       /* Finish processing unregister after unlock */
+       net_set_todo(dev);
+--- linux-2.6.20.12.orig/net/core/net-sysfs.c
++++ linux-2.6.20.12/net/core/net-sysfs.c
+@@ -440,9 +440,15 @@ static struct class net_class = {
+ #endif
+ };
++/* Delete sysfs entries but hold kobject reference until after all
++ * netdev references are gone.
++ */
+ void netdev_unregister_sysfs(struct net_device * net)
+ {
+-      class_device_del(&(net->class_dev));
++      struct device *dev = &(net->dev);
++
++      kobject_get(&dev->kobj);
++      device_del(dev);
+ }
+ /* Create sysfs entries for network device. */
diff --git a/queue-2.6.20/net-parse-ip-port-strings-correctly-in-in4_pton.patch b/queue-2.6.20/net-parse-ip-port-strings-correctly-in-in4_pton.patch
new file mode 100644 (file)
index 0000000..6217aba
--- /dev/null
@@ -0,0 +1,51 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:40:19 2007
+Date: Wed, 06 Jun 2007 22:40:27 -0700 (PDT)
+Message-Id: <20070606.224027.02298887.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: parse ip:port strings correctly in in4_pton
+
+From: Jerome Borsboom <j.borsboom@erasmusmc.nl>
+
+in4_pton converts a textual representation of an ip4 address
+into an integer representation. However, when the textual representation
+is of in the form ip:port, e.g. 192.168.1.1:5060, and 'delim' is set to
+-1, the function bails out with an error when reading the colon.
+
+It makes sense to allow the colon as a delimiting character without
+explicitly having to set it through the 'delim' variable as there can be
+no ambiguity in the point where the ip address is completely parsed. This
+function is indeed called from nf_conntrack_sip.c in this way to parse
+textual ip:port combinations which fails due to the reason stated above.
+
+Signed-off-by: Jerome Borsboom <j.borsboom@erasmusmc.nl>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/utils.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/net/core/utils.c
++++ linux-2.6.20.12/net/core/utils.c
+@@ -137,16 +137,16 @@ int in4_pton(const char *src, int srclen
+       while(1) {
+               int c;
+               c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
+-              if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM))) {
++              if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
+                       goto out;
+               }
+-              if (c & (IN6PTON_DOT | IN6PTON_DELIM)) {
++              if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+                       if (w == 0)
+                               goto out;
+                       *d++ = w & 0xff;
+                       w = 0;
+                       i++;
+-                      if (c & IN6PTON_DELIM) {
++                      if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
+                               if (i != 4)
+                                       goto out;
+                               break;
diff --git a/queue-2.6.20/net-wrong-timeout-value-in-sk_wait_data-v2.patch b/queue-2.6.20/net-wrong-timeout-value-in-sk_wait_data-v2.patch
new file mode 100644 (file)
index 0000000..8a3708b
--- /dev/null
@@ -0,0 +1,54 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:50:52 2007
+Date: Wed, 06 Jun 2007 22:51:03 -0700 (PDT)
+Message-Id: <20070606.225103.52166535.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: NET: "wrong timeout value" in sk_wait_data() v2
+
+From: Vasily Averin <vvs@sw.ru>
+
+sys_setsockopt() do not check properly timeout values for
+SO_RCVTIMEO/SO_SNDTIMEO, for example it's possible to set negative timeout
+values. POSIX do not defines behaviour for sys_setsockopt in case negative
+timeouts, but requires that setsockopt() shall fail with -EDOM if the send and
+receive timeout values are too big to fit into the timeout fields in the socket
+structure.
+In current implementation negative timeout can lead to error messages like
+"schedule_timeout: wrong timeout value".
+
+Proposed patch:
+- checks tv_usec and returns -EDOM if it is wrong
+- do not allows to set negative timeout values (sets 0 instead) and outputs
+ratelimited information message about such attempts.
+
+Signed-off-By: Vasily Averin <vvs@sw.ru>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ net/core/sock.c |   12 ++++++++++++
+ 1 file changed, 12 insertions(+)
+
+--- linux-2.6.20.12.orig/net/core/sock.c
++++ linux-2.6.20.12/net/core/sock.c
+@@ -204,7 +204,19 @@ static int sock_set_timeout(long *timeo_
+               return -EINVAL;
+       if (copy_from_user(&tv, optval, sizeof(tv)))
+               return -EFAULT;
++      if (tv.tv_usec < 0 || tv.tv_usec >= USEC_PER_SEC)
++              return -EDOM;
++      if (tv.tv_sec < 0) {
++              static int warned = 0;
++              *timeo_p = 0;
++              if (warned < 10 && net_ratelimit())
++                      warned++;
++                      printk(KERN_INFO "sock_set_timeout: `%s' (pid %d) "
++                             "tries to set negative timeout\n",
++                              current->comm, current->pid);
++              return 0;
++      }
+       *timeo_p = MAX_SCHEDULE_TIMEOUT;
+       if (tv.tv_sec == 0 && tv.tv_usec == 0)
+               return 0;
index 2b6be9fc19cb00d5e890fa2a40ef6c1c64049206..afe61756cea8d42c85d08fa5d4e99f7a642e0759 100644 (file)
@@ -16,4 +16,19 @@ alsa-usb-audio-explicitly-match-logitech-quickcam.patch
 v4l-dvb-budget-ci-fix-tuning-for-tdm-1316.patch
 kbuild-fixdep-segfault-on-pathological-string-o-death.patch
 ntfs_init_locked_inode-fix-array-indexing.patch
+icmp-fix-icmp_errors_use_inbound_ifaddr-sysctl.patch
+net-parse-ip-port-strings-correctly-in-in4_pton.patch
+ipsec-fix-panic-when-using-inter-address-familiy-ipsec-on-loopback.patch
+net-fix-bmsr_100-half-full-2-defines-in-linux-mii.h.patch
+ipv4-correct-rp_filter-help-text.patch
+sparc-linux-always-started-with-9600-8n1.patch
+net-wrong-timeout-value-in-sk_wait_data-v2.patch
+sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch
+sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch
+sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch
+tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch
+net-fix-race-condition-about-network-device-name-allocation.patch
+fix-af_unix-oops.patch
+ipv6-route-no-longer-handle-0-specially.patch
+sparc64-don-t-be-picky-about-virtual-dma-values-on-sun4v.patch
 netfilter-ip-nf-_conntrack_sctp-fix-remotely-triggerable-null-ptr-dereference.patch
diff --git a/queue-2.6.20/sparc-linux-always-started-with-9600-8n1.patch b/queue-2.6.20/sparc-linux-always-started-with-9600-8n1.patch
new file mode 100644 (file)
index 0000000..65aaf6f
--- /dev/null
@@ -0,0 +1,44 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:49:03 2007
+Date: Wed, 06 Jun 2007 22:49:14 -0700 (PDT)
+Message-Id: <20070606.224914.26966192.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC: Linux always started with 9600 8N1
+
+From: Jan Engelhardt <jengelh@gmx.de>
+
+The Linux kernel ignored the PROM's serial settings (115200,n,8,1 in
+my case). This was because mode_prop remained "ttyX-mode" (expected:
+"ttya-mode") due to the constness of string literals when used with
+"char *". Since there is no "ttyX-mode" property in the PROM, Linux
+always used the default 9600.
+
+[ Investigation of the suncore.s assembler reveals that gcc optimizied
+  away the stores, yet did not emit a warning, which is a pretty
+  anti-social thing to do and is the only reason this bug lived for
+  so long -DaveM ]
+
+Signed-off-by: Jan Engelhardt <jengelh@gmx.de>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ drivers/serial/suncore.c |    6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+--- linux-2.6.20.12.orig/drivers/serial/suncore.c
++++ linux-2.6.20.12/drivers/serial/suncore.c
+@@ -30,9 +30,9 @@ void
+ sunserial_console_termios(struct console *con)
+ {
+       char mode[16], buf[16], *s;
+-      char *mode_prop = "ttyX-mode";
+-      char *cd_prop = "ttyX-ignore-cd";
+-      char *dtr_prop = "ttyX-rts-dtr-off";
++      char mode_prop[] = "ttyX-mode";
++      char cd_prop[]   = "ttyX-ignore-cd";
++      char dtr_prop[]  = "ttyX-rts-dtr-off";
+       char *ssp_console_modes_prop = "ssp-console-modes";
+       int baud, bits, stop, cflag;
+       char parity;
diff --git a/queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch b/queue-2.6.20/sparc64-add-hypervisor-api-negotiation-and-fix-console-bugs.patch
new file mode 100644 (file)
index 0000000..e93fb10
--- /dev/null
@@ -0,0 +1,879 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:54:25 2007
+Date: Wed, 06 Jun 2007 22:54:33 -0700 (PDT)
+Message-Id: <20070606.225433.58454202.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Add hypervisor API negotiation and fix console bugs.
+
+Hypervisor interfaces need to be negotiated in order to use
+some API calls reliably.  So add a small set of interfaces
+to request API versions and query current settings.
+
+This allows us to fix some bugs in the hypervisor console:
+
+1) If we can negotiate API group CORE of at least major 1
+   minor 1 we can use con_read and con_write which can improve
+   console performance quite a bit.
+
+2) When we do a console write request, we should hold the
+   spinlock around the whole request, not a byte at a time.
+   What would happen is that it's easy for output from
+   different cpus to get mixed with each other.
+
+3) Use consistent udelay() based polling, udelay(1) each
+   loop with a limit of 1000 polls to handle stuck hypervisor
+   console.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/Makefile     |    2 
+ arch/sparc64/kernel/entry.S      |   94 +++++++++++++
+ arch/sparc64/kernel/hvapi.c      |  189 ++++++++++++++++++++++++++
+ arch/sparc64/kernel/setup.c      |    3 
+ drivers/serial/sunhv.c           |  276 ++++++++++++++++++++++++++++-----------
+ include/asm-sparc64/hypervisor.h |   83 +++++++++++
+ 6 files changed, 574 insertions(+), 73 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/Makefile
++++ linux-2.6.20.12/arch/sparc64/kernel/Makefile
+@@ -12,7 +12,7 @@ obj-y                := process.o setup.o cpu.o idprom
+                  irq.o ptrace.o time.o sys_sparc.o signal.o \
+                  unaligned.o central.o pci.o starfire.o semaphore.o \
+                  power.o sbus.o iommu_common.o sparc64_ksyms.o chmc.o \
+-                 visemul.o prom.o of_device.o
++                 visemul.o prom.o of_device.o hvapi.o
+ obj-$(CONFIG_STACKTRACE) += stacktrace.o
+ obj-$(CONFIG_PCI)      += ebus.o isa.o pci_common.o pci_iommu.o \
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/entry.S
++++ linux-2.6.20.12/arch/sparc64/kernel/entry.S
+@@ -1843,3 +1843,97 @@ sun4v_cpu_state:
+       mov     %o1, %o0
+ 1:    retl
+        nop
++
++      /* %o0: API group number
++       * %o1: pointer to unsigned long major number storage
++       * %o2: pointer to unsigned long minor number storage
++       *
++       * returns %o0: status
++       */
++      .globl  sun4v_get_version
++sun4v_get_version:
++      mov     HV_CORE_GET_VER, %o5
++      mov     %o1, %o3
++      mov     %o2, %o4
++      ta      HV_CORE_TRAP
++      stx     %o1, [%o3]
++      retl
++       stx    %o2, [%o4]
++
++      /* %o0: API group number
++       * %o1: desired major number
++       * %o2: desired minor number
++       * %o3: pointer to unsigned long actual minor number storage
++       *
++       * returns %o0: status
++       */
++      .globl  sun4v_set_version
++sun4v_set_version:
++      mov     HV_CORE_SET_VER, %o5
++      mov     %o3, %o4
++      ta      HV_CORE_TRAP
++      retl
++       stx    %o1, [%o4]
++
++      /* %o0: pointer to unsigned long status
++       *
++       * returns %o0: signed character
++       */
++      .globl  sun4v_con_getchar
++sun4v_con_getchar:
++      mov     %o0, %o4
++      mov     HV_FAST_CONS_GETCHAR, %o5
++      clr     %o0
++      clr     %o1
++      ta      HV_FAST_TRAP
++      stx     %o0, [%o4]
++      retl
++       sra    %o1, 0, %o0
++
++      /* %o0: signed long character
++       *
++       * returns %o0: status
++       */
++      .globl  sun4v_con_putchar
++sun4v_con_putchar:
++      mov     HV_FAST_CONS_PUTCHAR, %o5
++      ta      HV_FAST_TRAP
++      retl
++       sra    %o0, 0, %o0
++
++      /* %o0: buffer real address
++       * %o1: buffer size
++       * %o2: pointer to unsigned long bytes_read
++       *
++       * returns %o0: status
++       */
++      .globl  sun4v_con_read
++sun4v_con_read:
++      mov     %o2, %o4
++      mov     HV_FAST_CONS_READ, %o5
++      ta      HV_FAST_TRAP
++      brnz    %o0, 1f
++       cmp    %o1, -1         /* break */
++      be,a,pn %icc, 1f
++       mov    %o1, %o0
++      cmp     %o1, -2         /* hup */
++      be,a,pn %icc, 1f
++       mov    %o1, %o0
++      stx     %o1, [%o4]
++1:    retl
++       nop
++
++      /* %o0: buffer real address
++       * %o1: buffer size
++       * %o2: pointer to unsigned long bytes_written
++       *
++       * returns %o0: status
++       */
++      .globl  sun4v_con_write
++sun4v_con_write:
++      mov     %o2, %o4
++      mov     HV_FAST_CONS_WRITE, %o5
++      ta      HV_FAST_TRAP
++      stx     %o1, [%o4]
++      retl
++       nop
+--- /dev/null
++++ linux-2.6.20.12/arch/sparc64/kernel/hvapi.c
+@@ -0,0 +1,189 @@
++/* hvapi.c: Hypervisor API management.
++ *
++ * Copyright (C) 2007 David S. Miller <davem@davemloft.net>
++ */
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/slab.h>
++
++#include <asm/hypervisor.h>
++#include <asm/oplib.h>
++
++/* If the hypervisor indicates that the API setting
++ * calls are unsupported, by returning HV_EBADTRAP or
++ * HV_ENOTSUPPORTED, we assume that API groups with the
++ * PRE_API flag set are major 1 minor 0.
++ */
++struct api_info {
++      unsigned long group;
++      unsigned long major;
++      unsigned long minor;
++      unsigned int refcnt;
++      unsigned int flags;
++#define FLAG_PRE_API          0x00000001
++};
++
++static struct api_info api_table[] = {
++      { .group = HV_GRP_SUN4V,        .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_CORE,         .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_INTR,                                 },
++      { .group = HV_GRP_SOFT_STATE,                           },
++      { .group = HV_GRP_PCI,          .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_LDOM,                                 },
++      { .group = HV_GRP_SVC_CHAN,     .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_NCS,          .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_NIAG_PERF,    .flags = FLAG_PRE_API   },
++      { .group = HV_GRP_FIRE_PERF,                            },
++      { .group = HV_GRP_DIAG,         .flags = FLAG_PRE_API   },
++};
++
++static DEFINE_SPINLOCK(hvapi_lock);
++
++static struct api_info *__get_info(unsigned long group)
++{
++      int i;
++
++      for (i = 0; i < ARRAY_SIZE(api_table); i++) {
++              if (api_table[i].group == group)
++                      return &api_table[i];
++      }
++      return NULL;
++}
++
++static void __get_ref(struct api_info *p)
++{
++      p->refcnt++;
++}
++
++static void __put_ref(struct api_info *p)
++{
++      if (--p->refcnt == 0) {
++              unsigned long ignore;
++
++              sun4v_set_version(p->group, 0, 0, &ignore);
++              p->major = p->minor = 0;
++      }
++}
++
++/* Register a hypervisor API specification.  It indicates the
++ * API group and desired major+minor.
++ *
++ * If an existing API registration exists '0' (success) will
++ * be returned if it is compatible with the one being registered.
++ * Otherwise a negative error code will be returned.
++ *
++ * Otherwise an attempt will be made to negotiate the requested
++ * API group/major/minor with the hypervisor, and errors returned
++ * if that does not succeed.
++ */
++int sun4v_hvapi_register(unsigned long group, unsigned long major,
++                       unsigned long *minor)
++{
++      struct api_info *p;
++      unsigned long flags;
++      int ret;
++
++      spin_lock_irqsave(&hvapi_lock, flags);
++      p = __get_info(group);
++      ret = -EINVAL;
++      if (p) {
++              if (p->refcnt) {
++                      ret = -EINVAL;
++                      if (p->major == major) {
++                              *minor = p->minor;
++                              ret = 0;
++                      }
++              } else {
++                      unsigned long actual_minor;
++                      unsigned long hv_ret;
++
++                      hv_ret = sun4v_set_version(group, major, *minor,
++                                                 &actual_minor);
++                      ret = -EINVAL;
++                      if (hv_ret == HV_EOK) {
++                              *minor = actual_minor;
++                              p->major = major;
++                              p->minor = actual_minor;
++                              ret = 0;
++                      } else if (hv_ret == HV_EBADTRAP ||
++                                 HV_ENOTSUPPORTED) {
++                              if (p->flags & FLAG_PRE_API) {
++                                      if (major == 1) {
++                                              p->major = 1;
++                                              p->minor = 0;
++                                              *minor = 0;
++                                              ret = 0;
++                                      }
++                              }
++                      }
++              }
++
++              if (ret == 0)
++                      __get_ref(p);
++      }
++      spin_unlock_irqrestore(&hvapi_lock, flags);
++
++      return ret;
++}
++EXPORT_SYMBOL(sun4v_hvapi_register);
++
++void sun4v_hvapi_unregister(unsigned long group)
++{
++      struct api_info *p;
++      unsigned long flags;
++
++      spin_lock_irqsave(&hvapi_lock, flags);
++      p = __get_info(group);
++      if (p)
++              __put_ref(p);
++      spin_unlock_irqrestore(&hvapi_lock, flags);
++}
++EXPORT_SYMBOL(sun4v_hvapi_unregister);
++
++int sun4v_hvapi_get(unsigned long group,
++                  unsigned long *major,
++                  unsigned long *minor)
++{
++      struct api_info *p;
++      unsigned long flags;
++      int ret;
++
++      spin_lock_irqsave(&hvapi_lock, flags);
++      ret = -EINVAL;
++      p = __get_info(group);
++      if (p && p->refcnt) {
++              *major = p->major;
++              *minor = p->minor;
++              ret = 0;
++      }
++      spin_unlock_irqrestore(&hvapi_lock, flags);
++
++      return ret;
++}
++EXPORT_SYMBOL(sun4v_hvapi_get);
++
++void __init sun4v_hvapi_init(void)
++{
++      unsigned long group, major, minor;
++
++      group = HV_GRP_SUN4V;
++      major = 1;
++      minor = 0;
++      if (sun4v_hvapi_register(group, major, &minor))
++              goto bad;
++
++      group = HV_GRP_CORE;
++      major = 1;
++      minor = 1;
++      if (sun4v_hvapi_register(group, major, &minor))
++              goto bad;
++
++      return;
++
++bad:
++      prom_printf("HVAPI: Cannot register API group "
++                  "%lx with major(%u) minor(%u)\n",
++                  group, major, minor);
++      prom_halt();
++}
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/setup.c
++++ linux-2.6.20.12/arch/sparc64/kernel/setup.c
+@@ -269,6 +269,7 @@ void __init per_cpu_patch(void)
+ void __init sun4v_patch(void)
+ {
++      extern void sun4v_hvapi_init(void);
+       struct sun4v_1insn_patch_entry *p1;
+       struct sun4v_2insn_patch_entry *p2;
+@@ -300,6 +301,8 @@ void __init sun4v_patch(void)
+               p2++;
+       }
++
++      sun4v_hvapi_init();
+ }
+ #ifdef CONFIG_SMP
+--- linux-2.6.20.12.orig/drivers/serial/sunhv.c
++++ linux-2.6.20.12/drivers/serial/sunhv.c
+@@ -1,6 +1,6 @@
+ /* sunhv.c: Serial driver for SUN4V hypervisor console.
+  *
+- * Copyright (C) 2006 David S. Miller (davem@davemloft.net)
++ * Copyright (C) 2006, 2007 David S. Miller (davem@davemloft.net)
+  */
+ #include <linux/module.h>
+@@ -35,57 +35,51 @@
+ #define CON_BREAK     ((long)-1)
+ #define CON_HUP               ((long)-2)
+-static inline long hypervisor_con_getchar(long *status)
+-{
+-      register unsigned long func asm("%o5");
+-      register unsigned long arg0 asm("%o0");
+-      register unsigned long arg1 asm("%o1");
+-
+-      func = HV_FAST_CONS_GETCHAR;
+-      arg0 = 0;
+-      arg1 = 0;
+-      __asm__ __volatile__("ta        %6"
+-                           : "=&r" (func), "=&r" (arg0), "=&r" (arg1)
+-                           : "0" (func), "1" (arg0), "2" (arg1),
+-                             "i" (HV_FAST_TRAP));
++#define IGNORE_BREAK  0x1
++#define IGNORE_ALL    0x2
+-      *status = arg0;
++static char *con_write_page;
++static char *con_read_page;
+-      return (long) arg1;
+-}
++static int hung_up = 0;
+-static inline long hypervisor_con_putchar(long ch)
++static void transmit_chars_putchar(struct uart_port *port, struct circ_buf *xmit)
+ {
+-      register unsigned long func asm("%o5");
+-      register unsigned long arg0 asm("%o0");
++      while (!uart_circ_empty(xmit)) {
++              long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+-      func = HV_FAST_CONS_PUTCHAR;
+-      arg0 = ch;
+-      __asm__ __volatile__("ta        %4"
+-                           : "=&r" (func), "=&r" (arg0)
+-                           : "0" (func), "1" (arg0), "i" (HV_FAST_TRAP));
++              if (status != HV_EOK)
++                      break;
+-      return (long) arg0;
++              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
++              port->icount.tx++;
++      }
+ }
+-#define IGNORE_BREAK  0x1
+-#define IGNORE_ALL    0x2
++static void transmit_chars_write(struct uart_port *port, struct circ_buf *xmit)
++{
++      while (!uart_circ_empty(xmit)) {
++              unsigned long ra = __pa(xmit->buf + xmit->tail);
++              unsigned long len, status, sent;
+-static int hung_up = 0;
++              len = CIRC_CNT_TO_END(xmit->head, xmit->tail,
++                                    UART_XMIT_SIZE);
++              status = sun4v_con_write(ra, len, &sent);
++              if (status != HV_EOK)
++                      break;
++              xmit->tail = (xmit->tail + sent) & (UART_XMIT_SIZE - 1);
++              port->icount.tx += sent;
++      }
++}
+-static struct tty_struct *receive_chars(struct uart_port *port)
++static int receive_chars_getchar(struct uart_port *port, struct tty_struct *tty)
+ {
+-      struct tty_struct *tty = NULL;
+       int saw_console_brk = 0;
+       int limit = 10000;
+-      if (port->info != NULL)         /* Unopened serial console */
+-              tty = port->info->tty;
+-
+       while (limit-- > 0) {
+               long status;
+-              long c = hypervisor_con_getchar(&status);
+-              unsigned char flag;
++              long c = sun4v_con_getchar(&status);
+               if (status == HV_EWOULDBLOCK)
+                       break;
+@@ -110,27 +104,90 @@ static struct tty_struct *receive_chars(
+                       continue;
+               }
+-              flag = TTY_NORMAL;
+               port->icount.rx++;
+-              if (c == CON_BREAK) {
+-                      port->icount.brk++;
+-                      if (uart_handle_break(port))
+-                              continue;
+-                      flag = TTY_BREAK;
+-              }
+               if (uart_handle_sysrq_char(port, c))
+                       continue;
+-              if ((port->ignore_status_mask & IGNORE_ALL) ||
+-                  ((port->ignore_status_mask & IGNORE_BREAK) &&
+-                   (c == CON_BREAK)))
++              tty_insert_flip_char(tty, c, TTY_NORMAL);
++      }
++
++      return saw_console_brk;
++}
++
++static int receive_chars_read(struct uart_port *port, struct tty_struct *tty)
++{
++      int saw_console_brk = 0;
++      int limit = 10000;
++
++      while (limit-- > 0) {
++              unsigned long ra = __pa(con_read_page);
++              unsigned long bytes_read, i;
++              long stat = sun4v_con_read(ra, PAGE_SIZE, &bytes_read);
++
++              if (stat != HV_EOK) {
++                      bytes_read = 0;
++
++                      if (stat == CON_BREAK) {
++                              if (uart_handle_break(port))
++                                      continue;
++                              saw_console_brk = 1;
++                              *con_read_page = 0;
++                              bytes_read = 1;
++                      } else if (stat == CON_HUP) {
++                              hung_up = 1;
++                              uart_handle_dcd_change(port, 0);
++                              continue;
++                      } else {
++                              /* HV_EWOULDBLOCK, etc.  */
++                              break;
++                      }
++              }
++
++              if (hung_up) {
++                      hung_up = 0;
++                      uart_handle_dcd_change(port, 1);
++              }
++
++              for (i = 0; i < bytes_read; i++)
++                      uart_handle_sysrq_char(port, con_read_page[i]);
++
++              if (tty == NULL)
+                       continue;
+-              tty_insert_flip_char(tty, c, flag);
++              port->icount.rx += bytes_read;
++
++              tty_insert_flip_string(tty, con_read_page, bytes_read);
+       }
+-      if (saw_console_brk)
++      return saw_console_brk;
++}
++
++struct sunhv_ops {
++      void (*transmit_chars)(struct uart_port *port, struct circ_buf *xmit);
++      int (*receive_chars)(struct uart_port *port, struct tty_struct *tty);
++};
++
++static struct sunhv_ops bychar_ops = {
++      .transmit_chars = transmit_chars_putchar,
++      .receive_chars = receive_chars_getchar,
++};
++
++static struct sunhv_ops bywrite_ops = {
++      .transmit_chars = transmit_chars_write,
++      .receive_chars = receive_chars_read,
++};
++
++static struct sunhv_ops *sunhv_ops = &bychar_ops;
++
++static struct tty_struct *receive_chars(struct uart_port *port)
++{
++      struct tty_struct *tty = NULL;
++
++      if (port->info != NULL)         /* Unopened serial console */
++              tty = port->info->tty;
++
++      if (sunhv_ops->receive_chars(port, tty))
+               sun_do_break();
+       return tty;
+@@ -147,15 +204,7 @@ static void transmit_chars(struct uart_p
+       if (uart_circ_empty(xmit) || uart_tx_stopped(port))
+               return;
+-      while (!uart_circ_empty(xmit)) {
+-              long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
+-
+-              if (status != HV_EOK)
+-                      break;
+-
+-              xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1);
+-              port->icount.tx++;
+-      }
++      sunhv_ops->transmit_chars(port, xmit);
+       if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS)
+               uart_write_wakeup(port);
+@@ -212,7 +261,7 @@ static void sunhv_start_tx(struct uart_p
+       struct circ_buf *xmit = &port->info->xmit;
+       while (!uart_circ_empty(xmit)) {
+-              long status = hypervisor_con_putchar(xmit->buf[xmit->tail]);
++              long status = sun4v_con_putchar(xmit->buf[xmit->tail]);
+               if (status != HV_EOK)
+                       break;
+@@ -231,9 +280,10 @@ static void sunhv_send_xchar(struct uart
+       spin_lock_irqsave(&port->lock, flags);
+       while (limit-- > 0) {
+-              long status = hypervisor_con_putchar(ch);
++              long status = sun4v_con_putchar(ch);
+               if (status == HV_EOK)
+                       break;
++              udelay(1);
+       }
+       spin_unlock_irqrestore(&port->lock, flags);
+@@ -254,15 +304,15 @@ static void sunhv_break_ctl(struct uart_
+ {
+       if (break_state) {
+               unsigned long flags;
+-              int limit = 1000000;
++              int limit = 10000;
+               spin_lock_irqsave(&port->lock, flags);
+               while (limit-- > 0) {
+-                      long status = hypervisor_con_putchar(CON_BREAK);
++                      long status = sun4v_con_putchar(CON_BREAK);
+                       if (status == HV_EOK)
+                               break;
+-                      udelay(2);
++                      udelay(1);
+               }
+               spin_unlock_irqrestore(&port->lock, flags);
+@@ -359,38 +409,99 @@ static struct uart_driver sunhv_reg = {
+ static struct uart_port *sunhv_port;
+-static inline void sunhv_console_putchar(struct uart_port *port, char c)
++/* Copy 's' into the con_write_page, decoding "\n" into
++ * "\r\n" along the way.  We have to return two lengths
++ * because the caller needs to know how much to advance
++ * 's' and also how many bytes to output via con_write_page.
++ */
++static int fill_con_write_page(const char *s, unsigned int n,
++                             unsigned long *page_bytes)
+ {
++      const char *orig_s = s;
++      char *p = con_write_page;
++      int left = PAGE_SIZE;
++
++      while (n--) {
++              if (*s == '\n') {
++                      if (left < 2)
++                              break;
++                      *p++ = '\r';
++                      left--;
++              } else if (left < 1)
++                      break;
++              *p++ = *s++;
++              left--;
++      }
++      *page_bytes = p - con_write_page;
++      return s - orig_s;
++}
++
++static void sunhv_console_write_paged(struct console *con, const char *s, unsigned n)
++{
++      struct uart_port *port = sunhv_port;
+       unsigned long flags;
+-      int limit = 1000000;
+       spin_lock_irqsave(&port->lock, flags);
++      while (n > 0) {
++              unsigned long ra = __pa(con_write_page);
++              unsigned long page_bytes;
++              unsigned int cpy = fill_con_write_page(s, n,
++                                                     &page_bytes);
++
++              n -= cpy;
++              s += cpy;
++              while (page_bytes > 0) {
++                      unsigned long written;
++                      int limit = 1000000;
++
++                      while (limit--) {
++                              unsigned long stat;
++
++                              stat = sun4v_con_write(ra, page_bytes,
++                                                     &written);
++                              if (stat == HV_EOK)
++                                      break;
++                              udelay(1);
++                      }
++                      if (limit <= 0)
++                              break;
++                      page_bytes -= written;
++                      ra += written;
++              }
++      }
++      spin_unlock_irqrestore(&port->lock, flags);
++}
++
++static inline void sunhv_console_putchar(struct uart_port *port, char c)
++{
++      int limit = 1000000;
+       while (limit-- > 0) {
+-              long status = hypervisor_con_putchar(c);
++              long status = sun4v_con_putchar(c);
+               if (status == HV_EOK)
+                       break;
+-              udelay(2);
++              udelay(1);
+       }
+-
+-      spin_unlock_irqrestore(&port->lock, flags);
+ }
+-static void sunhv_console_write(struct console *con, const char *s, unsigned n)
++static void sunhv_console_write_bychar(struct console *con, const char *s, unsigned n)
+ {
+       struct uart_port *port = sunhv_port;
++      unsigned long flags;
+       int i;
++      spin_lock_irqsave(&port->lock, flags);
+       for (i = 0; i < n; i++) {
+               if (*s == '\n')
+                       sunhv_console_putchar(port, '\r');
+               sunhv_console_putchar(port, *s++);
+       }
++      spin_unlock_irqrestore(&port->lock, flags);
+ }
+ static struct console sunhv_console = {
+       .name   =       "ttyHV",
+-      .write  =       sunhv_console_write,
++      .write  =       sunhv_console_write_bychar,
+       .device =       uart_console_device,
+       .flags  =       CON_PRINTBUFFER,
+       .index  =       -1,
+@@ -410,6 +521,7 @@ static inline struct console *SUNHV_CONS
+ static int __devinit hv_probe(struct of_device *op, const struct of_device_id *match)
+ {
+       struct uart_port *port;
++      unsigned long minor;
+       int err;
+       if (op->irqs[0] == 0xffffffff)
+@@ -419,6 +531,22 @@ static int __devinit hv_probe(struct of_
+       if (unlikely(!port))
+               return -ENOMEM;
++      minor = 1;
++      if (sun4v_hvapi_register(HV_GRP_CORE, 1, &minor) == 0 &&
++          minor >= 1) {
++              err = -ENOMEM;
++              con_write_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
++              if (!con_write_page)
++                      goto out_free_port;
++
++              con_read_page = kzalloc(PAGE_SIZE, GFP_KERNEL);
++              if (!con_read_page)
++                      goto out_free_con_write_page;
++
++              sunhv_console.write = sunhv_console_write_paged;
++              sunhv_ops = &bywrite_ops;
++      }
++
+       sunhv_port = port;
+       port->line = 0;
+@@ -437,7 +565,7 @@ static int __devinit hv_probe(struct of_
+       err = uart_register_driver(&sunhv_reg);
+       if (err)
+-              goto out_free_port;
++              goto out_free_con_read_page;
+       sunhv_reg.tty_driver->name_base = sunhv_reg.minor - 64;
+       sunserial_current_minor += 1;
+@@ -463,6 +591,12 @@ out_unregister_driver:
+       sunserial_current_minor -= 1;
+       uart_unregister_driver(&sunhv_reg);
++out_free_con_read_page:
++      kfree(con_read_page);
++
++out_free_con_write_page:
++      kfree(con_write_page);
++
+ out_free_port:
+       kfree(port);
+       sunhv_port = NULL;
+--- linux-2.6.20.12.orig/include/asm-sparc64/hypervisor.h
++++ linux-2.6.20.12/include/asm-sparc64/hypervisor.h
+@@ -940,6 +940,54 @@ struct hv_fault_status {
+  */
+ #define HV_FAST_CONS_PUTCHAR          0x61
++/* con_read()
++ * TRAP:      HV_FAST_TRAP
++ * FUNCTION:  HV_FAST_CONS_READ
++ * ARG0:      buffer real address
++ * ARG1:      buffer size in bytes
++ * RET0:      status
++ * RET1:      bytes read or BREAK or HUP
++ * ERRORS:    EWOULDBLOCK     No character available.
++ *
++ * Reads characters into a buffer from the console device.  If no
++ * character is available then an EWOULDBLOCK error is returned.
++ * If a character is available, then the returned status is EOK
++ * and the number of bytes read into the given buffer is provided
++ * in RET1.
++ *
++ * A virtual BREAK is represented by the 64-bit RET1 value -1.
++ *
++ * A virtual HUP signal is represented by the 64-bit RET1 value -2.
++ *
++ * If BREAK or HUP are indicated, no bytes were read into buffer.
++ */
++#define HV_FAST_CONS_READ             0x62
++
++/* con_write()
++ * TRAP:      HV_FAST_TRAP
++ * FUNCTION:  HV_FAST_CONS_WRITE
++ * ARG0:      buffer real address
++ * ARG1:      buffer size in bytes
++ * RET0:      status
++ * RET1:      bytes written
++ * ERRORS:    EWOULDBLOCK     Output buffer currently full, would block
++ *
++ * Send a characters in buffer to the console device.  Breaks must be
++ * sent using con_putchar().
++ */
++#define HV_FAST_CONS_WRITE            0x63
++
++#ifndef __ASSEMBLY__
++extern long sun4v_con_getchar(long *status);
++extern long sun4v_con_putchar(long c);
++extern long sun4v_con_read(unsigned long buffer,
++                         unsigned long size,
++                         unsigned long *bytes_read);
++extern unsigned long sun4v_con_write(unsigned long buffer,
++                                   unsigned long size,
++                                   unsigned long *bytes_written);
++#endif
++
+ /* Trap trace services.
+  *
+  * The hypervisor provides a trap tracing capability for privileged
+@@ -2121,8 +2169,41 @@ struct hv_mmu_statistics {
+ #define HV_FAST_MMUSTAT_INFO          0x103
+ /* Function numbers for HV_CORE_TRAP.  */
+-#define HV_CORE_VER                   0x00
++#define HV_CORE_SET_VER                       0x00
+ #define HV_CORE_PUTCHAR                       0x01
+ #define HV_CORE_EXIT                  0x02
++#define HV_CORE_GET_VER                       0x03
++
++/* Hypervisor API groups for use with HV_CORE_SET_VER and
++ * HV_CORE_GET_VER.
++ */
++#define HV_GRP_SUN4V                  0x0000
++#define HV_GRP_CORE                   0x0001
++#define HV_GRP_INTR                   0x0002
++#define HV_GRP_SOFT_STATE             0x0003
++#define HV_GRP_PCI                    0x0100
++#define HV_GRP_LDOM                   0x0101
++#define HV_GRP_SVC_CHAN                       0x0102
++#define HV_GRP_NCS                    0x0103
++#define HV_GRP_NIAG_PERF              0x0200
++#define HV_GRP_FIRE_PERF              0x0201
++#define HV_GRP_DIAG                   0x0300
++
++#ifndef __ASSEMBLY__
++extern unsigned long sun4v_get_version(unsigned long group,
++                                     unsigned long *major,
++                                     unsigned long *minor);
++extern unsigned long sun4v_set_version(unsigned long group,
++                                     unsigned long major,
++                                     unsigned long minor,
++                                     unsigned long *actual_minor);
++
++extern int sun4v_hvapi_register(unsigned long group, unsigned long major,
++                              unsigned long *minor);
++extern void sun4v_hvapi_unregister(unsigned long group);
++extern int sun4v_hvapi_get(unsigned long group,
++                         unsigned long *major,
++                         unsigned long *minor);
++#endif
+ #endif /* !(_SPARC64_HYPERVISOR_H) */
diff --git a/queue-2.6.20/sparc64-don-t-be-picky-about-virtual-dma-values-on-sun4v.patch b/queue-2.6.20/sparc64-don-t-be-picky-about-virtual-dma-values-on-sun4v.patch
new file mode 100644 (file)
index 0000000..cd5a2b3
--- /dev/null
@@ -0,0 +1,90 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:59:13 2007
+Date: Wed, 06 Jun 2007 22:59:24 -0700 (PDT)
+Message-Id: <20070606.225924.88342677.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Don't be picky about virtual-dma values on sun4v.
+
+Handle arbitrary base and length values as long as they
+are multiples of IO_PAGE_SIZE.
+
+Bug found by Arun Kumar Rao.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+[chrisw: backport to 2.6.20]
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/pci_sun4v.c |   36 ++++++++++--------------------------
+ 1 file changed, 10 insertions(+), 26 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/pci_sun4v.c
++++ linux-2.6.20.12/arch/sparc64/kernel/pci_sun4v.c
+@@ -10,6 +10,7 @@
+ #include <linux/slab.h>
+ #include <linux/interrupt.h>
+ #include <linux/percpu.h>
++#include <linux/log2.h>
+ #include <asm/pbm.h>
+ #include <asm/iommu.h>
+@@ -994,9 +995,8 @@ static void pci_sun4v_iommu_init(struct 
+ {
+       struct pci_iommu *iommu = pbm->iommu;
+       struct property *prop;
+-      unsigned long num_tsb_entries, sz;
++      unsigned long num_tsb_entries, sz, tsbsize;
+       u32 vdma[2], dma_mask, dma_offset;
+-      int tsbsize;
+       prop = of_find_property(pbm->prom_node, "virtual-dma", NULL);
+       if (prop) {
+@@ -1010,31 +1010,15 @@ static void pci_sun4v_iommu_init(struct 
+               vdma[1] = 0x80000000;
+       }
+-      dma_mask = vdma[0];
+-      switch (vdma[1]) {
+-              case 0x20000000:
+-                      dma_mask |= 0x1fffffff;
+-                      tsbsize = 64;
+-                      break;
+-
+-              case 0x40000000:
+-                      dma_mask |= 0x3fffffff;
+-                      tsbsize = 128;
+-                      break;
+-
+-              case 0x80000000:
+-                      dma_mask |= 0x7fffffff;
+-                      tsbsize = 256;
+-                      break;
+-
+-              default:
+-                      prom_printf("PCI-SUN4V: strange virtual-dma size.\n");
+-                      prom_halt();
++      if ((vdma[0] | vdma[1]) & ~IO_PAGE_MASK) {
++              prom_printf("PCI-SUN4V: strange virtual-dma[%08x:%08x].\n",
++                          vdma[0], vdma[1]);
++              prom_halt();
+       };
+-      tsbsize *= (8 * 1024);
+-
+-      num_tsb_entries = tsbsize / sizeof(iopte_t);
++      dma_mask = (roundup_pow_of_two(vdma[1]) - 1UL);
++      num_tsb_entries = vdma[1] / IO_PAGE_SIZE;
++      tsbsize = num_tsb_entries * sizeof(iopte_t);
+       dma_offset = vdma[0];
+@@ -1045,7 +1029,7 @@ static void pci_sun4v_iommu_init(struct 
+       iommu->dma_addr_mask = dma_mask;
+       /* Allocate and initialize the free area map.  */
+-      sz = num_tsb_entries / 8;
++      sz = (num_tsb_entries + 7) / 8;
+       sz = (sz + 7UL) & ~7UL;
+       iommu->arena.map = kzalloc(sz, GFP_KERNEL);
+       if (!iommu->arena.map) {
diff --git a/queue-2.6.20/sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch b/queue-2.6.20/sparc64-fix-_page_exec_4u-check-in-sun4u-i-tlb-miss-handler.patch
new file mode 100644 (file)
index 0000000..1f166e3
--- /dev/null
@@ -0,0 +1,38 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:56:08 2007
+Date: Wed, 06 Jun 2007 22:56:19 -0700 (PDT)
+Message-Id: <20070606.225619.91314293.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Fix _PAGE_EXEC_4U check in sun4u I-TLB miss handler.
+
+It was using an immediate _PAGE_EXEC_4U value in an 'and'
+instruction to perform the test.  This doesn't work because
+the immediate field is signed 13-bit, this the mask being
+tested against the PTE was 0x1000 sign-extended to 32-bits
+instead of just plain 0x1000.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/itlb_miss.S |    4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/itlb_miss.S
++++ linux-2.6.20.12/arch/sparc64/kernel/itlb_miss.S
+@@ -11,12 +11,12 @@
+ /* ITLB ** ICACHE line 2: TSB compare and TLB load    */
+       bne,pn  %xcc, tsb_miss_itlb             ! Miss
+        mov    FAULT_CODE_ITLB, %g3
+-      andcc   %g5, _PAGE_EXEC_4U, %g0         ! Executable?
++      sethi   %hi(_PAGE_EXEC_4U), %g4
++      andcc   %g5, %g4, %g0                   ! Executable?
+       be,pn   %xcc, tsb_do_fault
+        nop                                    ! Delay slot, fill me
+       stxa    %g5, [%g0] ASI_ITLB_DATA_IN     ! Load TLB
+       retry                                   ! Trap done
+-      nop
+ /* ITLB ** ICACHE line 3:                             */
+       nop
diff --git a/queue-2.6.20/sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch b/queue-2.6.20/sparc64-fix-two-bugs-wrt.-kernel-4mb-tsb.patch
new file mode 100644 (file)
index 0000000..5b62c1a
--- /dev/null
@@ -0,0 +1,114 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 22:52:23 2007
+Date: Wed, 06 Jun 2007 22:52:35 -0700 (PDT)
+Message-Id: <20070606.225235.53338976.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: SPARC64: Fix two bugs wrt. kernel 4MB TSB.
+
+1) The TSB lookup was not using the correct hash mask.
+
+2) It was not aligned on a boundary equal to it's size,
+   which is required by the sun4v Hypervisor.
+
+wasn't having it's return value checked, and that bug will be fixed up
+as well in a subsequent changeset.
+
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+
+---
+ arch/sparc64/kernel/head.S |   31 ++++++++++++++++++++++++++-----
+ arch/sparc64/mm/init.c     |    7 +++++--
+ include/asm-sparc64/tsb.h  |    2 +-
+ 3 files changed, 32 insertions(+), 8 deletions(-)
+
+--- linux-2.6.20.12.orig/arch/sparc64/kernel/head.S
++++ linux-2.6.20.12/arch/sparc64/kernel/head.S
+@@ -653,33 +653,54 @@ setup_tba:
+        restore
+ sparc64_boot_end:
+-#include "ktlb.S"
+-#include "tsb.S"
+ #include "etrap.S"
+ #include "rtrap.S"
+ #include "winfixup.S"
+ #include "entry.S"
+ #include "sun4v_tlb_miss.S"
+ #include "sun4v_ivec.S"
++#include "ktlb.S"
++#include "tsb.S"
+ /*
+  * The following skip makes sure the trap table in ttable.S is aligned
+  * on a 32K boundary as required by the v9 specs for TBA register.
+  *
+  * We align to a 32K boundary, then we have the 32K kernel TSB,
+- * then the 32K aligned trap table.
++ * the 64K kernel 4MB TSB, and then the 32K aligned trap table.
+  */
+ 1:
+       .skip   0x4000 + _start - 1b
++! 0x0000000000408000
++
+       .globl  swapper_tsb
+ swapper_tsb:
+       .skip   (32 * 1024)
+-! 0x0000000000408000
+-
++      .globl  swapper_4m_tsb
++swapper_4m_tsb:
++      .skip   (64 * 1024)
++
++! 0x0000000000420000
++
++      /* Some care needs to be exercised if you try to move the
++       * location of the trap table relative to other things.  For
++       * one thing there are br* instructions in some of the
++       * trap table entires which branch back to code in ktlb.S
++       * Those instructions can only handle a signed 16-bit
++       * displacement.
++       *
++       * There is a binutils bug (bugzilla #4558) which causes
++       * the relocation overflow checks for such instructions to
++       * not be done correctly.  So bintuils will not notice the
++       * error and will instead write junk into the relocation and
++       * you'll have an unbootable kernel.
++       */
+ #include "ttable.S"
++! 0x0000000000428000
++
+ #include "systbls.S"
+       .data
+--- linux-2.6.20.12.orig/arch/sparc64/mm/init.c
++++ linux-2.6.20.12/arch/sparc64/mm/init.c
+@@ -60,8 +60,11 @@ unsigned long kern_linear_pte_xor[2] __r
+ unsigned long kpte_linear_bitmap[KPTE_BITMAP_BYTES / sizeof(unsigned long)];
+ #ifndef CONFIG_DEBUG_PAGEALLOC
+-/* A special kernel TSB for 4MB and 256MB linear mappings.  */
+-struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
++/* A special kernel TSB for 4MB and 256MB linear mappings.
++ * Space is allocated for this right after the trap table
++ * in arch/sparc64/kernel/head.S
++ */
++extern struct tsb swapper_4m_tsb[KERNEL_TSB4M_NENTRIES];
+ #endif
+ #define MAX_BANKS     32
+--- linux-2.6.20.12.orig/include/asm-sparc64/tsb.h
++++ linux-2.6.20.12/include/asm-sparc64/tsb.h
+@@ -271,7 +271,7 @@ extern struct tsb_phys_patch_entry __tsb
+ #define KERN_TSB4M_LOOKUP_TL1(TAG, REG1, REG2, REG3, REG4, OK_LABEL) \
+       sethi           %hi(swapper_4m_tsb), REG1; \
+       or              REG1, %lo(swapper_4m_tsb), REG1; \
+-      and             TAG, (KERNEL_TSB_NENTRIES - 1), REG2; \
++      and             TAG, (KERNEL_TSB4M_NENTRIES - 1), REG2; \
+       sllx            REG2, 4, REG2; \
+       add             REG1, REG2, REG2; \
+       KTSB_LOAD_QUAD(REG2, REG3); \
diff --git a/queue-2.6.20/tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch b/queue-2.6.20/tcp-use-default-32768-61000-outgoing-port-range-in-all-cases.patch
new file mode 100644 (file)
index 0000000..46b00b3
--- /dev/null
@@ -0,0 +1,57 @@
+From stable-bounces@linux.kernel.org  Wed Jun  6 23:01:11 2007
+Date: Wed, 06 Jun 2007 23:01:05 -0700 (PDT)
+Message-Id: <20070606.230105.57444963.davem@davemloft.net>
+To: stable@kernel.org
+From: David Miller <davem@davemloft.net>
+Cc: bunk@stusta.de
+Subject: TCP: Use default 32768-61000 outgoing port range in all cases.
+
+From: Mark Glines <mark@glines.org>
+
+This diff changes the default port range used for outgoing connections,
+from "use 32768-61000 in most cases, but use N-4999 on small boxes
+(where N is a multiple of 1024, depending on just *how* small the box
+is)" to just "use 32768-61000 in all cases".
+
+I don't believe there are any drawbacks to this change, and it keeps
+outgoing connection ports farther away from the mess of
+IANA-registered ports.
+
+Signed-off-by: Mark Glines <mark@glines.org>
+Signed-off-by: David S. Miller <davem@davemloft.net>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+ net/ipv4/inet_connection_sock.c |    4 +---
+ net/ipv4/tcp.c                  |    3 ---
+ 2 files changed, 1 insertion(+), 6 deletions(-)
+
+--- linux-2.6.20.12.orig/net/ipv4/inet_connection_sock.c
++++ linux-2.6.20.12/net/ipv4/inet_connection_sock.c
+@@ -31,10 +31,8 @@ EXPORT_SYMBOL(inet_csk_timer_bug_msg);
+ /*
+  * This array holds the first and last local port number.
+- * For high-usage systems, use sysctl to change this to
+- * 32768-61000
+  */
+-int sysctl_local_port_range[2] = { 1024, 4999 };
++int sysctl_local_port_range[2] = { 32768, 61000 };
+ int inet_csk_bind_conflict(const struct sock *sk,
+                          const struct inet_bind_bucket *tb)
+--- linux-2.6.20.12.orig/net/ipv4/tcp.c
++++ linux-2.6.20.12/net/ipv4/tcp.c
+@@ -2445,13 +2445,10 @@ void __init tcp_init(void)
+                       order++)
+               ;
+       if (order >= 4) {
+-              sysctl_local_port_range[0] = 32768;
+-              sysctl_local_port_range[1] = 61000;
+               tcp_death_row.sysctl_max_tw_buckets = 180000;
+               sysctl_tcp_max_orphans = 4096 << (order - 4);
+               sysctl_max_syn_backlog = 1024;
+       } else if (order < 3) {
+-              sysctl_local_port_range[0] = 1024 * (3 - order);
+               tcp_death_row.sysctl_max_tw_buckets >>= (3 - order);
+               sysctl_tcp_max_orphans >>= (3 - order);
+               sysctl_max_syn_backlog = 128;