<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.linux.kernel.commits.head">
    <title>gmane.linux.kernel.commits.head</title>
    <link>http://blog.gmane.org/gmane.linux.kernel.commits.head</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323192"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323191"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323190"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323189"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323188"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323187"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323186"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323185"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323184"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323183"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323182"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323181"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323180"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323179"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323178"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323177"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323176"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323175"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323174"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.linux.kernel.commits.head/323173"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323192">
    <title>sparc: use the new generic strnlen_user() function</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323192</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=2c66f623631709aa5f2e4c14c7e089682e7394a3
Commit:     2c66f623631709aa5f2e4c14c7e089682e7394a3
Parent:     5723aa993d83803157c22327e90cd59e3dcbe879
Author:     David Miller &amp;lt;davem&amp;lt; at &amp;gt;davemloft.net&amp;gt;
AuthorDate: Sat May 26 11:14:27 2012 -0700
Committer:  Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
CommitDate: Sat May 26 11:33:54 2012 -0700

    sparc: use the new generic strnlen_user() function
    
    This throws away the sparc-specific functions in favor of the generic
    optimized version.
    
    Signed-off-by: Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
---
 arch/sparc/Kconfig                  |    1 +
 arch/sparc/include/asm/uaccess_32.h |   22 +------
 arch/sparc/include/asm/uaccess_64.h |    8 +-
 arch/sparc/lib/Makefile             |    1 -
 arch/sparc/lib/ksyms.c              |    2 -
 arch/sparc/lib/strlen_user_32.S     |  109 -----------------------------------
 arch/sparc/lib/strlen_user_64.S     |   97 -------------------------------
 7 files changed, 9 insertions(+), 231 deletions(-)

diff --git a/arch/sparc/Kconfig b/arch/sparc/Kconfig
index 15e9e05..83bd051 100644
--- a/arch/sparc/Kconfig
+++ b/arch/sparc/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -35,6 +35,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config SPARC
 select GENERIC_CMOS_UPDATE
 select GENERIC_CLOCKEVENTS
 select GENERIC_STRNCPY_FROM_USER
+select GENERIC_STRNLEN_USER
 
 config SPARC32
 def_bool !64BIT
diff --git a/arch/sparc/include/asm/uaccess_32.h b/arch/sparc/include/asm/uaccess_32.h
index 59586b5..53a28dd 100644
--- a/arch/sparc/include/asm/uaccess_32.h
+++ b/arch/sparc/include/asm/uaccess_32.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -16,6 +16,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #ifndef __ASSEMBLY__
 
+#include &amp;lt;asm/processor.h&amp;gt;
+
 #define ARCH_HAS_SORT_EXTABLE
 #define ARCH_HAS_SEARCH_EXTABLE
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -304,24 +306,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned long clear_user(void __user *addr, unsigned long n)
 return n;
 }
 
-extern long __strlen_user(const char __user *);
-extern long __strnlen_user(const char __user *, long len);
-
-static inline long strlen_user(const char __user *str)
-{
-if (!access_ok(VERIFY_READ, str, 0))
-return 0;
-else
-return __strlen_user(str);
-}
-
-static inline long strnlen_user(const char __user *str, long len)
-{
-if (!access_ok(VERIFY_READ, str, 0))
-return 0;
-else
-return __strnlen_user(str, len);
-}
+extern __must_check long strlen_user(const char __user *str);
+extern __must_check long strnlen_user(const char __user *str, long n);
 
 #endif  /* __ASSEMBLY__ */
 
diff --git a/arch/sparc/include/asm/uaccess_64.h b/arch/sparc/include/asm/uaccess_64.h
index dcdfb89..7c831d8 100644
--- a/arch/sparc/include/asm/uaccess_64.h
+++ b/arch/sparc/include/asm/uaccess_64.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -17,6 +17,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #ifndef __ASSEMBLY__
 
+#include &amp;lt;asm/processor.h&amp;gt;
+
 /*
  * Sparc64 is segmented, though more like the M68K than the I386.
  * We use the secondary ASI to address user memory, which references a
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -257,11 +259,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern unsigned long __must_check __clear_user(void __user *, unsigned long);
 
 #define clear_user __clear_user
 
-extern long __strlen_user(const char __user *);
-extern long __strnlen_user(const char __user *, long len);
+extern __must_check long strlen_user(const char __user *str);
+extern __must_check long strnlen_user(const char __user *str, long n);
 
-#define strlen_user __strlen_user
-#define strnlen_user __strnlen_user
 #define __copy_to_user_inatomic ___copy_to_user
 #define __copy_from_user_inatomic ___copy_from_user
 
diff --git a/arch/sparc/lib/Makefile b/arch/sparc/lib/Makefile
index 943d98d..dff4096 100644
--- a/arch/sparc/lib/Makefile
+++ b/arch/sparc/lib/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -10,7 +10,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; lib-y                 += strlen.o
 lib-y                 += checksum_$(BITS).o
 lib-$(CONFIG_SPARC32) += blockops.o
 lib-y                 += memscan_$(BITS).o memcmp.o strncmp_$(BITS).o
-lib-y                 += strlen_user_$(BITS).o
 lib-$(CONFIG_SPARC32) += divdi3.o udivdi3.o
 lib-$(CONFIG_SPARC32) += copy_user.o locks.o
 lib-$(CONFIG_SPARC64) += atomic_64.o
diff --git a/arch/sparc/lib/ksyms.c b/arch/sparc/lib/ksyms.c
index 6b278ab..3b31218 100644
--- a/arch/sparc/lib/ksyms.c
+++ b/arch/sparc/lib/ksyms.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -15,8 +15,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 /* string functions */
 EXPORT_SYMBOL(strlen);
-EXPORT_SYMBOL(__strlen_user);
-EXPORT_SYMBOL(__strnlen_user);
 EXPORT_SYMBOL(strncmp);
 
 /* mem* functions */
diff --git a/arch/sparc/lib/strlen_user_32.S b/arch/sparc/lib/strlen_user_32.S
deleted file mode 100644
index 8c8a371..0000000
--- a/arch/sparc/lib/strlen_user_32.S
+++ /dev/null
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,109 +0,0 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-/* strlen_user.S: Sparc optimized strlen_user code
- *
- * Return length of string in userspace including terminating 0
- * or 0 for error
- *
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996 David S. Miller (davem&amp;lt; at &amp;gt;caip.rutgers.edu)
- * Copyright (C) 1996 Jakub Jelinek (jj&amp;lt; at &amp;gt;sunsite.mff.cuni.cz)
- */
-
-#define LO_MAGIC 0x01010101
-#define HI_MAGIC 0x80808080
-
-10:
-ldub[%o0], %o5
-cmp%o5, 0
-be1f
- add%o0, 1, %o0
-andcc%o0, 3, %g0
-be4f
- or%o4, %lo(HI_MAGIC), %o3
-11:
-ldub[%o0], %o5
-cmp%o5, 0
-be2f
- add%o0, 1, %o0
-andcc%o0, 3, %g0
-be5f
- sethi%hi(LO_MAGIC), %o4
-12:
-ldub[%o0], %o5
-cmp%o5, 0
-be3f
- add%o0, 1, %o0
-b13f
- or%o4, %lo(LO_MAGIC), %o2
-1:
-retl
- mov1, %o0
-2:
-retl
- mov2, %o0
-3:
-retl
- mov3, %o0
-
-.align 4
-.global __strlen_user, __strnlen_user
-__strlen_user:
-sethi%hi(32768), %o1
-__strnlen_user:
-mov%o1, %g1
-mov%o0, %o1
-andcc%o0, 3, %g0
-bne10b
- sethi%hi(HI_MAGIC), %o4
-or%o4, %lo(HI_MAGIC), %o3
-4:
-sethi%hi(LO_MAGIC), %o4
-5:
-or%o4, %lo(LO_MAGIC), %o2
-13:
-ld[%o0], %o5
-2:
-sub%o5, %o2, %o4
-andcc%o4, %o3, %g0
-bne82f
- add%o0, 4, %o0
-sub%o0, %o1, %g2
-81:cmp%g2, %g1
-blu13b
- mov%o0, %o4
-ba,a1f
-
-/* Check every byte. */
-82:srl%o5, 24, %g5
-andcc%g5, 0xff, %g0
-be1f
- add%o0, -3, %o4
-srl%o5, 16, %g5
-andcc%g5, 0xff, %g0
-be1f
- add%o4, 1, %o4
-srl%o5, 8, %g5
-andcc%g5, 0xff, %g0
-be1f
- add%o4, 1, %o4
-andcc%o5, 0xff, %g0
-bne81b
- sub%o0, %o1, %g2
-
-add%o4, 1, %o4
-1:
-retl
- sub%o4, %o1, %o0
-
-.section .fixup,#alloc,#execinstr
-.align4
-9:
-retl
- clr%o0
-
-.section __ex_table,#alloc
-.align4
-
-.word10b, 9b
-.word11b, 9b
-.word12b, 9b
-.word13b, 9b
diff --git a/arch/sparc/lib/strlen_user_64.S b/arch/sparc/lib/strlen_user_64.S
deleted file mode 100644
index c3df71f..0000000
--- a/arch/sparc/lib/strlen_user_64.S
+++ /dev/null
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,97 +0,0 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
-/* strlen_user.S: Sparc64 optimized strlen_user code
- *
- * Return length of string in userspace including terminating 0
- * or 0 for error
- *
- * Copyright (C) 1991,1996 Free Software Foundation
- * Copyright (C) 1996,1999 David S. Miller (davem&amp;lt; at &amp;gt;redhat.com)
- * Copyright (C) 1996,1997 Jakub Jelinek (jj&amp;lt; at &amp;gt;sunsite.mff.cuni.cz)
- */
-
-#include &amp;lt;linux/linkage.h&amp;gt;
-#include &amp;lt;asm/asi.h&amp;gt;
-
-#define LO_MAGIC 0x01010101
-#define HI_MAGIC 0x80808080
-
-.align 4
-ENTRY(__strlen_user)
-sethi%hi(32768), %o1
-ENTRY(__strnlen_user)
-mov%o1, %g1
-mov%o0, %o1
-andcc%o0, 3, %g0
-be,pt%icc, 9f
- sethi%hi(HI_MAGIC), %o4
-10:lduba[%o0] %asi, %o5
-brz,pn%o5, 21f
- add%o0, 1, %o0
-andcc%o0, 3, %g0
-be,pn%icc, 4f
- or%o4, %lo(HI_MAGIC), %o3
-11:lduba[%o0] %asi, %o5
-brz,pn%o5, 22f
- add%o0, 1, %o0
-andcc%o0, 3, %g0
-be,pt%icc, 13f
- srl%o3, 7, %o2
-12:lduba[%o0] %asi, %o5
-brz,pn%o5, 23f
- add%o0, 1, %o0
-ba,pt%icc, 2f
-15: lda[%o0] %asi, %o5
-9:or%o4, %lo(HI_MAGIC), %o3
-4:srl%o3, 7, %o2
-13:lda[%o0] %asi, %o5
-2:sub%o5, %o2, %o4
-andcc%o4, %o3, %g0
-bne,pn%icc, 82f
- add%o0, 4, %o0
-sub%o0, %o1, %g2
-81:cmp%g2, %g1
-blu,pt%icc, 13b
- mov%o0, %o4
-ba,a,pt%xcc, 1f
-
-/* Check every byte. */
-82:srl%o5, 24, %g7
-andcc%g7, 0xff, %g0
-be,pn%icc, 1f
- add%o0, -3, %o4
-srl%o5, 16, %g7
-andcc%g7, 0xff, %g0
-be,pn%icc, 1f
- add%o4, 1, %o4
-srl%o5, 8, %g7
-andcc%g7, 0xff, %g0
-be,pn%icc, 1f
- add%o4, 1, %o4
-andcc%o5, 0xff, %g0
-bne,pt%icc, 81b
- sub%o0, %o1, %g2
-add%o4, 1, %o4
-1:retl
- sub%o4, %o1, %o0
-21:retl
- mov1, %o0
-22:retl
- mov2, %o0
-23:retl
- mov3, %o0
-ENDPROC(__strlen_user)
-ENDPROC(__strnlen_user)
-
-        .section .fixup,#alloc,#execinstr
-        .align  4
-30:
-        retl
-         clr    %o0
-
-.section __ex_table,"a"
-.align4
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-26T18:34:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323191">
    <title>x86: use the new generic strnlen_user() function</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323191</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=5723aa993d83803157c22327e90cd59e3dcbe879
Commit:     5723aa993d83803157c22327e90cd59e3dcbe879
Parent:     a08c5356a3aaf638c41897ae4169de18db89595e
Author:     Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
AuthorDate: Sat May 26 11:09:53 2012 -0700
Committer:  Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
CommitDate: Sat May 26 11:33:54 2012 -0700

    x86: use the new generic strnlen_user() function
    
    This throws away the old x86-specific functions in favor of the generic
    optimized version.
    
    Signed-off-by: Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
---
 arch/x86/Kconfig                  |    1 +
 arch/x86/include/asm/uaccess.h    |    3 ++
 arch/x86/include/asm/uaccess_32.h |   17 -------------
 arch/x86/include/asm/uaccess_64.h |    3 --
 arch/x86/lib/usercopy_32.c        |   41 -------------------------------
 arch/x86/lib/usercopy_64.c        |   48 -------------------------------------
 6 files changed, 4 insertions(+), 109 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 3220d44..d700811 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -94,6 +94,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config X86
 select GENERIC_TIME_VSYSCALL if X86_64
 select KTIME_SCALAR if X86_32
 select GENERIC_STRNCPY_FROM_USER
+select GENERIC_STRNLEN_USER
 
 config INSTRUCTION_DECODER
 def_bool (KPROBES || PERF_EVENTS || UPROBES)
diff --git a/arch/x86/include/asm/uaccess.h b/arch/x86/include/asm/uaccess.h
index 1354fac..04cd688 100644
--- a/arch/x86/include/asm/uaccess.h
+++ b/arch/x86/include/asm/uaccess.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -566,6 +566,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; copy_from_user_nmi(void *to, const void __user *from, unsigned long n);
 extern __must_check long
 strncpy_from_user(char *dst, const char __user *src, long count);
 
+extern __must_check long strlen_user(const char __user *str);
+extern __must_check long strnlen_user(const char __user *str, long n);
+
 /*
  * movsl can be slow when source and dest are not both 8-byte aligned
  */
diff --git a/arch/x86/include/asm/uaccess_32.h b/arch/x86/include/asm/uaccess_32.h
index 8084bc7..576e39b 100644
--- a/arch/x86/include/asm/uaccess_32.h
+++ b/arch/x86/include/asm/uaccess_32.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -213,23 +213,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned long __must_check copy_from_user(void *to,
 return n;
 }
 
-/**
- * strlen_user: - Get the size of a string in user space.
- * &amp;lt; at &amp;gt;str: The string to measure.
- *
- * Context: User context only.  This function may sleep.
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- *
- * If there is a limit on the length of a valid string, you may wish to
- * consider using strnlen_user() instead.
- */
-#define strlen_user(str) strnlen_user(str, LONG_MAX)
-
-long strnlen_user(const char __user *str, long n);
 unsigned long __must_check clear_user(void __user *mem, unsigned long len);
 unsigned long __must_check __clear_user(void __user *mem, unsigned long len);
 
diff --git a/arch/x86/include/asm/uaccess_64.h b/arch/x86/include/asm/uaccess_64.h
index fcd4b6f..8e796fb 100644
--- a/arch/x86/include/asm/uaccess_64.h
+++ b/arch/x86/include/asm/uaccess_64.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -208,9 +208,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int __copy_in_user(void __user *dst, const void __user *src, unsigned size)
 }
 }
 
-__must_check long strnlen_user(const char __user *str, long n);
-__must_check long __strnlen_user(const char __user *str, long n);
-__must_check long strlen_user(const char __user *str);
 __must_check unsigned long clear_user(void __user *mem, unsigned long len);
 __must_check unsigned long __clear_user(void __user *mem, unsigned long len);
 
diff --git a/arch/x86/lib/usercopy_32.c b/arch/x86/lib/usercopy_32.c
index 883b216..1781b2f 100644
--- a/arch/x86/lib/usercopy_32.c
+++ b/arch/x86/lib/usercopy_32.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -95,47 +95,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; __clear_user(void __user *to, unsigned long n)
 }
 EXPORT_SYMBOL(__clear_user);
 
-/**
- * strnlen_user: - Get the size of a string in user space.
- * &amp;lt; at &amp;gt;s: The string to measure.
- * &amp;lt; at &amp;gt;n: The maximum valid length
- *
- * Get the size of a NUL-terminated string in user space.
- *
- * Returns the size of the string INCLUDING the terminating NUL.
- * On exception, returns 0.
- * If the string is too long, returns a value greater than &amp;lt; at &amp;gt;n.
- */
-long strnlen_user(const char __user *s, long n)
-{
-unsigned long mask = -__addr_ok(s);
-unsigned long res, tmp;
-
-might_fault();
-
-__asm__ __volatile__(
-"testl %0, %0\n"
-"jz 3f\n"
-"andl %0,%%ecx\n"
-"0:repne; scasb\n"
-"setne %%al\n"
-"subl %%ecx,%0\n"
-"addl %0,%%eax\n"
-"1:\n"
-".section .fixup,\"ax\"\n"
-"2:xorl %%eax,%%eax\n"
-"jmp 1b\n"
-"3:movb $1,%%al\n"
-"jmp 1b\n"
-".previous\n"
-_ASM_EXTABLE(0b,2b)
-:"=&amp;amp;r" (n), "=&amp;amp;D" (s), "=&amp;amp;a" (res), "=&amp;amp;c" (tmp)
-:"0" (n), "1" (s), "2" (0), "3" (mask)
-:"cc");
-return res &amp;amp; mask;
-}
-EXPORT_SYMBOL(strnlen_user);
-
 #ifdef CONFIG_X86_INTEL_USERCOPY
 static unsigned long
 __copy_user_intel(void __user *to, const void *from, unsigned long size)
diff --git a/arch/x86/lib/usercopy_64.c b/arch/x86/lib/usercopy_64.c
index 0d0326f..e5b130b 100644
--- a/arch/x86/lib/usercopy_64.c
+++ b/arch/x86/lib/usercopy_64.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -52,54 +52,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; unsigned long clear_user(void __user *to, unsigned long n)
 }
 EXPORT_SYMBOL(clear_user);
 
-/*
- * Return the size of a string (including the ending 0)
- *
- * Return 0 on exception, a value greater than N if too long
- */
-
-long __strnlen_user(const char __user *s, long n)
-{
-long res = 0;
-char c;
-
-while (1) {
-if (res&amp;gt;n)
-return n+1;
-if (__get_user(c, s))
-return 0;
-if (!c)
-return res+1;
-res++;
-s++;
-}
-}
-EXPORT_SYMBOL(__strnlen_user);
-
-long strnlen_user(const char __user *s, long n)
-{
-if (!access_ok(VERIFY_READ, s, 1))
-return 0;
-return __strnlen_user(s, n);
-}
-EXPORT_SYMBOL(strnlen_user);
-
-long strlen_user(const char __user *s)
-{
-long res = 0;
-char c;
-
-for (;;) {
-if (get_user(c, s))
-return 0;
-if (!c)
-return res+1;
-res++;
-s++;
-}
-}
-EXPORT_SYMBOL(strlen_user);
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-26T18:34:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323190">
    <title>lib: add generic strnlen_user() function</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323190</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=a08c5356a3aaf638c41897ae4169de18db89595e
Commit:     a08c5356a3aaf638c41897ae4169de18db89595e
Parent:     36126f8f2ed8168eb13aa0662b9b9585cba100a9
Author:     Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
AuthorDate: Sat May 26 11:06:38 2012 -0700
Committer:  Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
CommitDate: Sat May 26 11:33:53 2012 -0700

    lib: add generic strnlen_user() function
    
    This adds a new generic optimized strnlen_user() function that uses the
    &amp;lt;asm/word-at-a-time.h&amp;gt; infrastructure to portably do efficient string
    handling.
    
    In many ways, strnlen is much simpler than strncpy, and in particular we
    can always pre-align the words we load from memory.  That means that all
    the worries about alignment etc are a non-issue, so this one can easily
    be used on any architecture.  You obviously do have to do the
    appropriate word-at-a-time.h macros.
    
    Signed-off-by: Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
---
 lib/Kconfig        |    3 +
 lib/Makefile       |    1 +
 lib/strnlen_user.c |  138 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 142 insertions(+), 0 deletions(-)

diff --git a/lib/Kconfig b/lib/Kconfig
index 98230ac..64ddc44 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,6 +19,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config RATIONAL
 config GENERIC_STRNCPY_FROM_USER
 bool
 
+config GENERIC_STRNLEN_USER
+bool
+
 config GENERIC_FIND_FIRST_BIT
 bool
 
diff --git a/lib/Makefile b/lib/Makefile
index b98df50..77937a7 100644
--- a/lib/Makefile
+++ b/lib/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -126,6 +126,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; obj-$(CONFIG_CLZ_TAB) += clz_tab.o
 obj-$(CONFIG_DDR) += jedec_ddr_data.o
 
 obj-$(CONFIG_GENERIC_STRNCPY_FROM_USER) += strncpy_from_user.o
+obj-$(CONFIG_GENERIC_STRNLEN_USER) += strnlen_user.o
 
 hostprogs-y:= gen_crc32table
 clean-files:= crc32table.h
diff --git a/lib/strnlen_user.c b/lib/strnlen_user.c
new file mode 100644
index 0000000..90900ec
--- /dev/null
+++ b/lib/strnlen_user.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,138 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+#include &amp;lt;linux/kernel.h&amp;gt;
+#include &amp;lt;linux/export.h&amp;gt;
+#include &amp;lt;linux/uaccess.h&amp;gt;
+
+#include &amp;lt;asm/word-at-a-time.h&amp;gt;
+
+/* Set bits in the first 'n' bytes when loaded from memory */
+#ifdef __LITTLE_ENDIAN
+#  define aligned_byte_mask(n) ((1ul &amp;lt;&amp;lt; 8*(n))-1)
+#else
+#  define aligned_byte_mask(n) (~0xfful &amp;lt;&amp;lt; 8*(7-(n)))
+#endif
+
+/*
+ * Do a strnlen, return length of string *with* final '\0'.
+ * 'count' is the user-supplied count, while 'max' is the
+ * address space maximum.
+ *
+ * Return 0 for exceptions (which includes hitting the address
+ * space maximum), or 'count+1' if hitting the user-supplied
+ * maximum count.
+ *
+ * NOTE! We can sometimes overshoot the user-supplied maximum
+ * if it fits in a aligned 'long'. The caller needs to check
+ * the return value against "&amp;gt; max".
+ */
+static inline long do_strnlen_user(const char __user *src, unsigned long count, unsigned long max)
+{
+const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
+long align, res = 0;
+unsigned long c;
+
+/*
+ * Truncate 'max' to the user-specified limit, so that
+ * we only have one limit we need to check in the loop
+ */
+if (max &amp;gt; count)
+max = count;
+
+/*
+ * Do everything aligned. But that means that we
+ * need to also expand the maximum..
+ */
+align = (sizeof(long) - 1) &amp;amp; (unsigned long)src;
+src -= align;
+max += align;
+
+if (unlikely(__get_user(c,(unsigned long __user *)src)))
+return 0;
+c |= aligned_byte_mask(align);
+
+for (;;) {
+unsigned long data;
+if (has_zero(c, &amp;amp;data, &amp;amp;constants)) {
+data = prep_zero_mask(c, data, &amp;amp;constants);
+data = create_zero_mask(data);
+return res + find_zero(data) + 1 - align;
+}
+res += sizeof(unsigned long);
+if (unlikely(max &amp;lt; sizeof(unsigned long)))
+break;
+max -= sizeof(unsigned long);
+if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
+return 0;
+}
+res -= align;
+
+/*
+ * Uhhuh. We hit 'max'. But was that the user-specified maximum
+ * too? If so, return the marker for "too long".
+ */
+if (res &amp;gt;= count)
+return count+1;
+
+/*
+ * Nope: we hit the address space limit, and we still had more
+ * characters the caller would have wanted. That's 0.
+ */
+return 0;
+}
+
+/**
+ * strnlen_user: - Get the size of a user string INCLUDING final NUL.
+ * &amp;lt; at &amp;gt;str: The string to measure.
+ * &amp;lt; at &amp;gt;count: Maximum count (including NUL character)
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * If the string is too long, returns 'count+1'.
+ * On exception (or invalid count), returns 0.
+ */
+long strnlen_user(const char __user *str, long count)
+{
+unsigned long max_addr, src_addr;
+
+if (unlikely(count &amp;lt;= 0))
+return 0;
+
+max_addr = user_addr_max();
+src_addr = (unsigned long)str;
+if (likely(src_addr &amp;lt; max_addr)) {
+unsigned long max = max_addr - src_addr;
+return do_strnlen_user(str, count, max);
+}
+return 0;
+}
+EXPORT_SYMBOL(strnlen_user);
+
+/**
+ * strlen_user: - Get the size of a user string INCLUDING final NUL.
+ * &amp;lt; at &amp;gt;str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
+long strlen_user(const char __user *str)
+{
+unsigned long max_addr, src_addr;
+
+max_addr = user_addr_max();
+src_addr = (unsigned long)str;
+if (likely(src_addr &amp;lt; max_addr)) {
+unsigned long max = max_addr - src_addr;
+return do_strnlen_user(str, ~0ul, max);
+}
+return 0;
+}
+EXPORT_SYMBOL(strlen_user);
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-26T18:34:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323189">
    <title>word-at-a-time: make the interfaces truly generic</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323189</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=36126f8f2ed8168eb13aa0662b9b9585cba100a9
Commit:     36126f8f2ed8168eb13aa0662b9b9585cba100a9
Parent:     4ae73f2d53255c388d50bf83c1681112a6f9cba1
Author:     Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
AuthorDate: Sat May 26 10:43:17 2012 -0700
Committer:  Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
CommitDate: Sat May 26 11:33:40 2012 -0700

    word-at-a-time: make the interfaces truly generic
    
    This changes the interfaces in &amp;lt;asm/word-at-a-time.h&amp;gt; to be a bit more
    complicated, but a lot more generic.
    
    In particular, it allows us to really do the operations efficiently on
    both little-endian and big-endian machines, pretty much regardless of
    machine details.  For example, if you can rely on a fast population
    count instruction on your architecture, this will allow you to make your
    optimized &amp;lt;asm/word-at-a-time.h&amp;gt; file with that.
    
    NOTE! The "generic" version in include/asm-generic/word-at-a-time.h is
    not truly generic, it actually only works on big-endian.  Why? Because
    on little-endian the generic algorithms are wasteful, since you can
    inevitably do better. The x86 implementation is an example of that.
    
    (The only truly non-generic part of the asm-generic implementation is
    the "find_zero()" function, and you could make a little-endian version
    of it.  And if the Kbuild infrastructure allowed us to pick a particular
    header file, that would be lovely)
    
    The &amp;lt;asm/word-at-a-time.h&amp;gt; functions are as follows:
    
     - WORD_AT_A_TIME_CONSTANTS: specific constants that the algorithm
       uses.
    
     - has_zero(): take a word, and determine if it has a zero byte in it.
       It gets the word, the pointer to the constant pool, and a pointer to
       an intermediate "data" field it can set.
    
       This is the "quick-and-dirty" zero tester: it's what is run inside
       the hot loops.
    
     - "prep_zero_mask()": take the word, the data that has_zero() produced,
       and the constant pool, and generate an *exact* mask of which byte had
       the first zero.  This is run directly *outside* the loop, and allows
       the "has_zero()" function to answer the "is there a zero byte"
       question without necessarily getting exactly *which* byte is the
       first one to contain a zero.
    
       If you do multiple byte lookups concurrently (eg "hash_name()", which
       looks for both NUL and '/' bytes), after you've done the prep_zero_mask()
       phase, the result of those can be or'ed together to get the "either
       or" case.
    
     - The result from "prep_zero_mask()" can then be fed into "find_zero()"
       (to find the byte offset of the first byte that was zero) or into
       "zero_bytemask()" (to find the bytemask of the bytes preceding the
       zero byte).
    
       The existence of zero_bytemask() is optional, and is not necessary
       for the normal string routines.  But dentry name hashing needs it, so
       if you enable DENTRY_WORD_AT_A_TIME you need to expose it.
    
    This changes the generic strncpy_from_user() function and the dentry
    hashing functions to use these modified word-at-a-time interfaces.  This
    gets us back to the optimized state of the x86 strncpy that we lost in
    the previous commit when moving over to the generic version.
    
    Signed-off-by: Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linux-foundation.org&amp;gt;
---
 arch/openrisc/include/asm/Kbuild      |    1 +
 arch/sparc/include/asm/Kbuild         |    1 +
 arch/x86/include/asm/word-at-a-time.h |   32 ++++++++++++++++++--
 fs/namei.c                            |   22 +++++++------
 include/asm-generic/word-at-a-time.h  |   52 +++++++++++++++++++++++++++++++++
 lib/strncpy_from_user.c               |   47 ++++-------------------------
 6 files changed, 102 insertions(+), 53 deletions(-)

diff --git a/arch/openrisc/include/asm/Kbuild b/arch/openrisc/include/asm/Kbuild
index c936483..3f35c38 100644
--- a/arch/openrisc/include/asm/Kbuild
+++ b/arch/openrisc/include/asm/Kbuild
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,3 +66,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; generic-y += topology.h
 generic-y += types.h
 generic-y += ucontext.h
 generic-y += user.h
+generic-y += word-at-a-time.h
diff --git a/arch/sparc/include/asm/Kbuild b/arch/sparc/include/asm/Kbuild
index 2c2e388..67f83e0 100644
--- a/arch/sparc/include/asm/Kbuild
+++ b/arch/sparc/include/asm/Kbuild
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,3 +21,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; generic-y += div64.h
 generic-y += local64.h
 generic-y += irq_regs.h
 generic-y += local.h
+generic-y += word-at-a-time.h
diff --git a/arch/x86/include/asm/word-at-a-time.h b/arch/x86/include/asm/word-at-a-time.h
index ae03fac..5b23898 100644
--- a/arch/x86/include/asm/word-at-a-time.h
+++ b/arch/x86/include/asm/word-at-a-time.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -10,6 +10,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * bit count instruction, that might be better than the multiply
  * and shift, for example.
  */
+struct word_at_a_time {
+const unsigned long one_bits, high_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0x01), REPEAT_BYTE(0x80) }
 
 #ifdef CONFIG_64BIT
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -37,10 +42,31 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline long count_masked_bytes(long mask)
 
 #endif
 
-/* Return the high bit set in the first byte that is a zero */
-static inline unsigned long has_zero(unsigned long a)
+/* Return nonzero if it has a zero */
+static inline unsigned long has_zero(unsigned long a, unsigned long *bits, const struct word_at_a_time *c)
+{
+unsigned long mask = ((a - c-&amp;gt;one_bits) &amp;amp; ~a) &amp;amp; c-&amp;gt;high_bits;
+*bits = mask;
+return mask;
+}
+
+static inline unsigned long prep_zero_mask(unsigned long a, unsigned long bits, const struct word_at_a_time *c)
+{
+return bits;
+}
+
+static inline unsigned long create_zero_mask(unsigned long bits)
+{
+bits = (bits - 1) &amp;amp; ~bits;
+return bits &amp;gt;&amp;gt; 7;
+}
+
+/* The mask we created is directly usable as a bytemask */
+#define zero_bytemask(mask) (mask)
+
+static inline unsigned long find_zero(unsigned long mask)
 {
-return ((a - REPEAT_BYTE(0x01)) &amp;amp; ~a) &amp;amp; REPEAT_BYTE(0x80);
+return count_masked_bytes(mask);
 }
 
 /*
diff --git a/fs/namei.c b/fs/namei.c
index 93ff12b..c651f02 100644
--- a/fs/namei.c
+++ b/fs/namei.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1452,7 +1452,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; EXPORT_SYMBOL(full_name_hash);
  */
 static inline unsigned long hash_name(const char *name, unsigned int *hashp)
 {
-unsigned long a, mask, hash, len;
+unsigned long a, b, adata, bdata, mask, hash, len;
+const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 
 hash = a = 0;
 len = -sizeof(unsigned long);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1460,17 +1461,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned long hash_name(const char *name, unsigned int *hashp)
 hash = (hash + a) * 9;
 len += sizeof(unsigned long);
 a = load_unaligned_zeropad(name+len);
-/* Do we have any NUL or '/' bytes in this word? */
-mask = has_zero(a) | has_zero(a ^ REPEAT_BYTE('/'));
-} while (!mask);
-
-/* The mask *below* the first high bit set */
-mask = (mask - 1) &amp;amp; ~mask;
-mask &amp;gt;&amp;gt;= 7;
-hash += a &amp;amp; mask;
+b = a ^ REPEAT_BYTE('/');
+} while (!(has_zero(a, &amp;amp;adata, &amp;amp;constants) | has_zero(b, &amp;amp;bdata, &amp;amp;constants)));
+
+adata = prep_zero_mask(a, adata, &amp;amp;constants);
+bdata = prep_zero_mask(b, bdata, &amp;amp;constants);
+
+mask = create_zero_mask(adata | bdata);
+
+hash += a &amp;amp; zero_bytemask(mask);
 *hashp = fold_hash(hash);
 
-return len + count_masked_bytes(mask);
+return len + find_zero(mask);
 }
 
 #else
diff --git a/include/asm-generic/word-at-a-time.h b/include/asm-generic/word-at-a-time.h
new file mode 100644
index 0000000..3f21f1b
--- /dev/null
+++ b/include/asm-generic/word-at-a-time.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,52 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+#ifndef _ASM_WORD_AT_A_TIME_H
+#define _ASM_WORD_AT_A_TIME_H
+
+/*
+ * This says "generic", but it's actually big-endian only.
+ * Little-endian can use more efficient versions of these
+ * interfaces, see for example
+ * arch/x86/include/asm/word-at-a-time.h
+ * for those.
+ */
+
+#include &amp;lt;linux/kernel.h&amp;gt;
+
+struct word_at_a_time {
+const unsigned long high_bits, low_bits;
+};
+
+#define WORD_AT_A_TIME_CONSTANTS { REPEAT_BYTE(0xfe) + 1, REPEAT_BYTE(0x7f) }
+
+/* Bit set in the bytes that have a zero */
+static inline long prep_zero_mask(unsigned long val, unsigned long rhs, const struct word_at_a_time *c)
+{
+unsigned long mask = (val &amp;amp; c-&amp;gt;low_bits) + c-&amp;gt;low_bits;
+return ~(mask | rhs);
+}
+
+#define create_zero_mask(mask) (mask)
+
+static inline long find_zero(unsigned long mask)
+{
+long byte = 0;
+#ifdef CONFIG_64BIT
+if (mask &amp;gt;&amp;gt; 32)
+mask &amp;gt;&amp;gt;= 32;
+else
+byte = 4;
+#endif
+if (mask &amp;gt;&amp;gt; 16)
+mask &amp;gt;&amp;gt;= 16;
+else
+byte += 2;
+return (mask &amp;gt;&amp;gt; 8) ? byte : byte + 1;
+}
+
+static inline bool has_zero(unsigned long val, unsigned long *data, const struct word_at_a_time *c)
+{
+unsigned long rhs = val | c-&amp;gt;low_bits;
+*data = rhs;
+return (val + c-&amp;gt;high_bits) &amp;amp; ~rhs;
+}
+
+#endif /* _ASM_WORD_AT_A_TIME_H */
diff --git a/lib/strncpy_from_user.c b/lib/strncpy_from_user.c
index c4c09b0..bb2b201 100644
--- a/lib/strncpy_from_user.c
+++ b/lib/strncpy_from_user.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -4,37 +4,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/errno.h&amp;gt;
 
 #include &amp;lt;asm/byteorder.h&amp;gt;
-
-static inline long find_zero(unsigned long mask)
-{
-long byte = 0;
-
-#ifdef __BIG_ENDIAN
-#ifdef CONFIG_64BIT
-if (mask &amp;gt;&amp;gt; 32)
-mask &amp;gt;&amp;gt;= 32;
-else
-byte = 4;
-#endif
-if (mask &amp;gt;&amp;gt; 16)
-mask &amp;gt;&amp;gt;= 16;
-else
-byte += 2;
-return (mask &amp;gt;&amp;gt; 8) ? byte : byte + 1;
-#else
-#ifdef CONFIG_64BIT
-if (!((unsigned int) mask)) {
-mask &amp;gt;&amp;gt;= 32;
-byte = 4;
-}
-#endif
-if (!(mask &amp;amp; 0xffff)) {
-mask &amp;gt;&amp;gt;= 16;
-byte += 2;
-}
-return (mask &amp;amp; 0xff) ? byte : byte + 1;
-#endif
-}
+#include &amp;lt;asm/word-at-a-time.h&amp;gt;
 
 #ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
 #define IS_UNALIGNED(src, dst)0
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -51,8 +21,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline long find_zero(unsigned long mask)
  */
 static inline long do_strncpy_from_user(char *dst, const char __user *src, long count, unsigned long max)
 {
-const unsigned long high_bits = REPEAT_BYTE(0xfe) + 1;
-const unsigned long low_bits = REPEAT_BYTE(0x7f);
+const struct word_at_a_time constants = WORD_AT_A_TIME_CONSTANTS;
 long res = 0;
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,18 +35,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline long do_strncpy_from_user(char *dst, const char __user *src, long
 goto byte_at_a_time;
 
 while (max &amp;gt;= sizeof(unsigned long)) {
-unsigned long c, v, rhs;
+unsigned long c, data;
 
 /* Fall back to byte-at-a-time if we get a page fault */
 if (unlikely(__get_user(c,(unsigned long __user *)(src+res))))
 break;
-rhs = c | low_bits;
-v = (c + high_bits) &amp;amp; ~rhs;
 *(unsigned long *)(dst+res) = c;
-if (v) {
-v = (c &amp;amp; low_bits) + low_bits;
-v = ~(v | rhs);
-return res + find_zero(v);
+if (has_zero(c, &amp;amp;data, &amp;amp;constants)) {
+data = prep_zero_mask(c, data, &amp;amp;constants);
+data = create_zero_mask(data);
+return res + find_zero(data);
 }
 res += sizeof(unsigned long);
 max -= sizeof(unsigned long);
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-26T18:34:20</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323188">
    <title>arch/tile: Allow tilegx to build with either 16K or 64K page size</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323188</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=d5d14ed6f2db7287a5088e1350cf422bf72140b3
Commit:     d5d14ed6f2db7287a5088e1350cf422bf72140b3
Parent:     47d632f9f8f3ed62b21f725e98b726d65769b6d7
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Thu Mar 29 13:58:43 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:24 2012 -0400

    arch/tile: Allow tilegx to build with either 16K or 64K page size
    
    This change introduces new flags for the hv_install_context()
    API that passes a page table pointer to the hypervisor.  Clients
    can explicitly request 4K, 16K, or 64K small pages when they
    install a new context.  In practice, the page size is fixed at
    kernel compile time and the same size is always requested every
    time a new page table is installed.
    
    The &amp;lt;hv/hypervisor.h&amp;gt; header changes so that it provides more abstract
    macros for managing "page" things like PFNs and page tables.  For
    example there is now a HV_DEFAULT_PAGE_SIZE_SMALL instead of the old
    HV_PAGE_SIZE_SMALL.  The various PFN routines have been eliminated and
    only PA- or PTFN-based ones remain (since PTFNs are always expressed
    in fixed 2KB "page" size).  The page-table management macros are
    renamed with a leading underscore and take page-size arguments with
    the presumption that clients will use those macros in some single
    place to provide the "real" macros they will use themselves.
    
    I happened to notice the old hv_set_caching() API was totally broken
    (it assumed 4KB pages) so I changed it so it would nominally work
    correctly with other page sizes.
    
    Tag modules with the page size so you can't load a module built with
    a conflicting page size.  (And add a test for SMP while we're at it.)
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/Kconfig                    |   25 ++++
 arch/tile/include/asm/Kbuild         |    1 -
 arch/tile/include/asm/mmu.h          |    2 +-
 arch/tile/include/asm/mmu_context.h  |    8 +-
 arch/tile/include/asm/module.h       |   40 +++++++
 arch/tile/include/asm/page.h         |   13 ++-
 arch/tile/include/asm/pgalloc.h      |   92 +++++++++++----
 arch/tile/include/asm/pgtable.h      |   10 +-
 arch/tile/include/asm/pgtable_32.h   |   14 ++-
 arch/tile/include/asm/pgtable_64.h   |   28 +++--
 arch/tile/include/hv/drv_xgbe_intf.h |    2 +-
 arch/tile/include/hv/hypervisor.h    |  214 +++++++++++++++++++---------------
 arch/tile/kernel/head_32.S           |    8 +-
 arch/tile/kernel/head_64.S           |   22 ++--
 arch/tile/kernel/machine_kexec.c     |    7 +-
 arch/tile/kernel/setup.c             |    8 +-
 arch/tile/kernel/smp.c               |    2 +-
 arch/tile/lib/memcpy_tile64.c        |    8 +-
 arch/tile/mm/init.c                  |   11 +--
 arch/tile/mm/pgtable.c               |   27 ++---
 20 files changed, 345 insertions(+), 197 deletions(-)

diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 74239dd..38c3957 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -139,6 +139,31 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config NR_CPUS
   smaller kernel memory footprint results from using a smaller
   value on chips with fewer tiles.
 
+if TILEGX
+
+choice
+prompt "Kernel page size"
+default PAGE_SIZE_64KB
+help
+  This lets you select the page size of the kernel.  For best
+  performance on memory-intensive applications, a page size of 64KB
+  is recommended.  For workloads involving many small files, many
+  connections, etc., it may be better to select 16KB, which uses
+  memory more efficiently at some cost in TLB performance.
+
+  Note that this option is TILE-Gx specific; currently
+  TILEPro page size is set by rebuilding the hypervisor.
+
+config PAGE_SIZE_16KB
+bool "16KB"
+
+config PAGE_SIZE_64KB
+bool "64KB"
+
+endchoice
+
+endif
+
 source "kernel/time/Kconfig"
 
 source "kernel/Kconfig.hz"
diff --git a/arch/tile/include/asm/Kbuild b/arch/tile/include/asm/Kbuild
index 0bb4264..6b2e681 100644
--- a/arch/tile/include/asm/Kbuild
+++ b/arch/tile/include/asm/Kbuild
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,7 +21,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; generic-y += ipcbuf.h
 generic-y += irq_regs.h
 generic-y += kdebug.h
 generic-y += local.h
-generic-y += module.h
 generic-y += msgbuf.h
 generic-y += mutex.h
 generic-y += param.h
diff --git a/arch/tile/include/asm/mmu.h b/arch/tile/include/asm/mmu.h
index 92f94c7..e2c7890 100644
--- a/arch/tile/include/asm/mmu.h
+++ b/arch/tile/include/asm/mmu.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,7 +21,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct mm_context {
  * Written under the mmap_sem semaphore; read without the
  * semaphore but atomically, but it is conservatively set.
  */
-unsigned int priority_cached;
+unsigned long priority_cached;
 };
 
 typedef struct mm_context mm_context_t;
diff --git a/arch/tile/include/asm/mmu_context.h b/arch/tile/include/asm/mmu_context.h
index 15fb246..37f0b74 100644
--- a/arch/tile/include/asm/mmu_context.h
+++ b/arch/tile/include/asm/mmu_context.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -30,11 +30,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; init_new_context(struct task_struct *tsk, struct mm_struct *mm)
 return 0;
 }
 
-/* Note that arch/tile/kernel/head.S also calls hv_install_context() */
+/*
+ * Note that arch/tile/kernel/head_NN.S and arch/tile/mm/migrate_NN.S
+ * also call hv_install_context().
+ */
 static inline void __install_page_table(pgd_t *pgdir, int asid, pgprot_t prot)
 {
 /* FIXME: DIRECTIO should not always be set. FIXME. */
-int rc = hv_install_context(__pa(pgdir), prot, asid, HV_CTX_DIRECTIO);
+int rc = hv_install_context(__pa(pgdir), prot, asid,
+    HV_CTX_DIRECTIO | CTX_PAGE_FLAG);
 if (rc &amp;lt; 0)
 panic("hv_install_context failed: %d", rc);
 }
diff --git a/arch/tile/include/asm/module.h b/arch/tile/include/asm/module.h
new file mode 100644
index 0000000..44ed07c
--- /dev/null
+++ b/arch/tile/include/asm/module.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -0,0 +1,40 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
+/*
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
+ *
+ *   This program is free software; you can redistribute it and/or
+ *   modify it under the terms of the GNU General Public License
+ *   as published by the Free Software Foundation, version 2.
+ *
+ *   This program is distributed in the hope that it will be useful, but
+ *   WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ *   NON INFRINGEMENT.  See the GNU General Public License for
+ *   more details.
+ */
+
+#ifndef _ASM_TILE_MODULE_H
+#define _ASM_TILE_MODULE_H
+
+#include &amp;lt;arch/chip.h&amp;gt;
+
+#include &amp;lt;asm-generic/module.h&amp;gt;
+
+/* We can't use modules built with different page sizes. */
+#if defined(CONFIG_PAGE_SIZE_16KB)
+# define MODULE_PGSZ " 16KB"
+#elif defined(CONFIG_PAGE_SIZE_64KB)
+# define MODULE_PGSZ " 64KB"
+#else
+# define MODULE_PGSZ ""
+#endif
+
+/* We don't really support no-SMP so tag if someone tries. */
+#ifdef CONFIG_SMP
+#define MODULE_NOSMP ""
+#else
+#define MODULE_NOSMP " nosmp"
+#endif
+
+#define MODULE_ARCH_VERMAGIC CHIP_ARCH_NAME MODULE_PGSZ MODULE_NOSMP
+
+#endif /* _ASM_TILE_MODULE_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index db93518..c750943 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -20,8 +20,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;arch/chip.h&amp;gt;
 
 /* PAGE_SHIFT and HPAGE_SHIFT determine the page sizes. */
-#define PAGE_SHIFTHV_LOG2_PAGE_SIZE_SMALL
-#define HPAGE_SHIFTHV_LOG2_PAGE_SIZE_LARGE
+#if defined(CONFIG_PAGE_SIZE_16KB)
+#define PAGE_SHIFT14
+#define CTX_PAGE_FLAGHV_CTX_PG_SM_16K
+#elif defined(CONFIG_PAGE_SIZE_64KB)
+#define PAGE_SHIFT16
+#define CTX_PAGE_FLAGHV_CTX_PG_SM_64K
+#else
+#define PAGE_SHIFTHV_LOG2_DEFAULT_PAGE_SIZE_SMALL
+#define CTX_PAGE_FLAG0
+#endif
+#define HPAGE_SHIFTHV_LOG2_DEFAULT_PAGE_SIZE_LARGE
 
 #define PAGE_SIZE(_AC(1, UL) &amp;lt;&amp;lt; PAGE_SHIFT)
 #define HPAGE_SIZE(_AC(1, UL) &amp;lt;&amp;lt; HPAGE_SHIFT)
diff --git a/arch/tile/include/asm/pgalloc.h b/arch/tile/include/asm/pgalloc.h
index e919c0b..1b90250 100644
--- a/arch/tile/include/asm/pgalloc.h
+++ b/arch/tile/include/asm/pgalloc.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,24 +19,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/mm.h&amp;gt;
 #include &amp;lt;linux/mmzone.h&amp;gt;
 #include &amp;lt;asm/fixmap.h&amp;gt;
+#include &amp;lt;asm/page.h&amp;gt;
 #include &amp;lt;hv/hypervisor.h&amp;gt;
 
 /* Bits for the size of the second-level page table. */
-#define L2_KERNEL_PGTABLE_SHIFT \
-  (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL + HV_LOG2_PTE_SIZE)
+#define L2_KERNEL_PGTABLE_SHIFT _HV_LOG2_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
+
+/* How big is a kernel L2 page table? */
+#define L2_KERNEL_PGTABLE_SIZE (1UL &amp;lt;&amp;lt; L2_KERNEL_PGTABLE_SHIFT)
 
 /* We currently allocate user L2 page tables by page (unlike kernel L2s). */
-#if L2_KERNEL_PGTABLE_SHIFT &amp;lt; HV_LOG2_PAGE_SIZE_SMALL
-#define L2_USER_PGTABLE_SHIFT HV_LOG2_PAGE_SIZE_SMALL
+#if L2_KERNEL_PGTABLE_SHIFT &amp;lt; PAGE_SHIFT
+#define L2_USER_PGTABLE_SHIFT PAGE_SHIFT
 #else
 #define L2_USER_PGTABLE_SHIFT L2_KERNEL_PGTABLE_SHIFT
 #endif
 
 /* How many pages do we need, as an "order", for a user L2 page table? */
-#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - HV_LOG2_PAGE_SIZE_SMALL)
-
-/* How big is a kernel L2 page table? */
-#define L2_KERNEL_PGTABLE_SIZE (1 &amp;lt;&amp;lt; L2_KERNEL_PGTABLE_SHIFT)
+#define L2_USER_PGTABLE_ORDER (L2_USER_PGTABLE_SHIFT - PAGE_SHIFT)
 
 static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -50,14 +50,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void set_pmd(pmd_t *pmdp, pmd_t pmd)
 static inline void pmd_populate_kernel(struct mm_struct *mm,
        pmd_t *pmd, pte_t *ptep)
 {
-set_pmd(pmd, ptfn_pmd(__pa(ptep) &amp;gt;&amp;gt; HV_LOG2_PAGE_TABLE_ALIGN,
+set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(__pa(ptep)),
       __pgprot(_PAGE_PRESENT)));
 }
 
 static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
 pgtable_t page)
 {
-set_pmd(pmd, ptfn_pmd(HV_PFN_TO_PTFN(page_to_pfn(page)),
+set_pmd(pmd, ptfn_pmd(HV_CPA_TO_PTFN(PFN_PHYS(page_to_pfn(page))),
       __pgprot(_PAGE_PRESENT)));
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -68,8 +68,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
 extern pgd_t *pgd_alloc(struct mm_struct *mm);
 extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
 
-extern pgtable_t pte_alloc_one(struct mm_struct *mm, unsigned long address);
-extern void pte_free(struct mm_struct *mm, struct page *pte);
+extern pgtable_t pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
+   int order);
+extern void pgtable_free(struct mm_struct *mm, struct page *pte, int order);
+
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
+      unsigned long address)
+{
+return pgtable_alloc_one(mm, address, L2_USER_PGTABLE_ORDER);
+}
+
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
+{
+pgtable_free(mm, pte, L2_USER_PGTABLE_ORDER);
+}
 
 #define pmd_pgtable(pmd) pmd_page(pmd)
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -85,8 +97,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
 pte_free(mm, virt_to_page(pte));
 }
 
-extern void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
-   unsigned long address);
+extern void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte,
+       unsigned long address, int order);
+static inline void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
+  unsigned long address)
+{
+__pgtable_free_tlb(tlb, pte, address, L2_USER_PGTABLE_ORDER);
+}
 
 #define check_pgt_cache()do { } while (0)
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,19 +121,44 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void shatter_pmd(pmd_t *pmd);
 void shatter_huge_page(unsigned long addr);
 
 #ifdef __tilegx__
-/* We share a single page allocator for both L1 and L2 page tables. */
-#if HV_L1_SIZE != HV_L2_SIZE
-# error Rework assumption that L1 and L2 page tables are same size.
-#endif
-#define L1_USER_PGTABLE_ORDER L2_USER_PGTABLE_ORDER
+
 #define pud_populate(mm, pud, pmd) \
   pmd_populate_kernel((mm), (pmd_t *)(pud), (pte_t *)(pmd))
-#define pmd_alloc_one(mm, addr) \
-  ((pmd_t *)page_to_virt(pte_alloc_one((mm), (addr))))
-#define pmd_free(mm, pmdp) \
-  pte_free((mm), virt_to_page(pmdp))
-#define __pmd_free_tlb(tlb, pmdp, address) \
-  __pte_free_tlb((tlb), virt_to_page(pmdp), (address))
+
+/* Bits for the size of the L1 (intermediate) page table. */
+#define L1_KERNEL_PGTABLE_SHIFT _HV_LOG2_L1_SIZE(HPAGE_SHIFT)
+
+/* How big is a kernel L2 page table? */
+#define L1_KERNEL_PGTABLE_SIZE (1UL &amp;lt;&amp;lt; L1_KERNEL_PGTABLE_SHIFT)
+
+/* We currently allocate L1 page tables by page. */
+#if L1_KERNEL_PGTABLE_SHIFT &amp;lt; PAGE_SHIFT
+#define L1_USER_PGTABLE_SHIFT PAGE_SHIFT
+#else
+#define L1_USER_PGTABLE_SHIFT L1_KERNEL_PGTABLE_SHIFT
 #endif
 
+/* How many pages do we need, as an "order", for an L1 page table? */
+#define L1_USER_PGTABLE_ORDER (L1_USER_PGTABLE_SHIFT - PAGE_SHIFT)
+
+static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long address)
+{
+struct page *p = pgtable_alloc_one(mm, address, L1_USER_PGTABLE_ORDER);
+return (pmd_t *)page_to_virt(p);
+}
+
+static inline void pmd_free(struct mm_struct *mm, pmd_t *pmdp)
+{
+pgtable_free(mm, virt_to_page(pmdp), L1_USER_PGTABLE_ORDER);
+}
+
+static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
+  unsigned long address)
+{
+__pgtable_free_tlb(tlb, virt_to_page(pmdp), address,
+   L1_USER_PGTABLE_ORDER);
+}
+
+#endif /* __tilegx__ */
+
 #endif /* _ASM_TILE_PGALLOC_H */
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index ec907d4..319f482 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -27,8 +27,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/slab.h&amp;gt;
 #include &amp;lt;linux/list.h&amp;gt;
 #include &amp;lt;linux/spinlock.h&amp;gt;
+#include &amp;lt;linux/pfn.h&amp;gt;
 #include &amp;lt;asm/processor.h&amp;gt;
 #include &amp;lt;asm/fixmap.h&amp;gt;
+#include &amp;lt;asm/page.h&amp;gt;
 
 struct mm_struct;
 struct vm_area_struct;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -162,7 +164,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern void set_page_homes(void);
   (pgprot_t) { ((oldprot).val &amp;amp; ~_PAGE_ALL) | (newprot).val }
 
 /* Just setting the PFN to zero suffices. */
-#define pte_pgprot(x) hv_pte_set_pfn((x), 0)
+#define pte_pgprot(x) hv_pte_set_pa((x), 0)
 
 /*
  * For PTEs and PDEs, we must clear the Present bit first when
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -262,7 +264,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int pte_none(pte_t pte)
 
 static inline unsigned long pte_pfn(pte_t pte)
 {
-return hv_pte_get_pfn(pte);
+return PFN_DOWN(hv_pte_get_pa(pte));
 }
 
 /* Set or get the remote cache cpu in a pgprot with remote caching. */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -271,7 +273,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern int get_remote_cache_cpu(pgprot_t prot);
 
 static inline pte_t pfn_pte(unsigned long pfn, pgprot_t prot)
 {
-return hv_pte_set_pfn(prot, pfn);
+return hv_pte_set_pa(prot, PFN_PHYS(pfn));
 }
 
 /* Support for priority mappings. */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -471,7 +473,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned long pmd_page_vaddr(pmd_t pmd)
  * OK for pte_lockptr(), since we just end up with potentially one
  * lock being used for several pte_t arrays.
  */
-#define pmd_page(pmd) pfn_to_page(HV_PTFN_TO_PFN(pmd_ptfn(pmd)))
+#define pmd_page(pmd) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pmd_ptfn(pmd))))
 
 static inline void pmd_clear(pmd_t *pmdp)
 {
diff --git a/arch/tile/include/asm/pgtable_32.h b/arch/tile/include/asm/pgtable_32.h
index 27e20f6..4ce4a7a 100644
--- a/arch/tile/include/asm/pgtable_32.h
+++ b/arch/tile/include/asm/pgtable_32.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -20,11 +20,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * The level-1 index is defined by the huge page size.  A PGD is composed
  * of PTRS_PER_PGD pgd_t's and is the top level of the page table.
  */
-#define PGDIR_SHIFTHV_LOG2_PAGE_SIZE_LARGE
-#define PGDIR_SIZEHV_PAGE_SIZE_LARGE
+#define PGDIR_SHIFTHPAGE_SHIFT
+#define PGDIR_SIZEHPAGE_SIZE
 #define PGDIR_MASK(~(PGDIR_SIZE-1))
-#define PTRS_PER_PGD(1 &amp;lt;&amp;lt; (32 - PGDIR_SHIFT))
-#define SIZEOF_PGD(PTRS_PER_PGD * sizeof(pgd_t))
+#define PTRS_PER_PGD_HV_L1_ENTRIES(HPAGE_SHIFT)
+#define PGD_INDEX(va)_HV_L1_INDEX(va, HPAGE_SHIFT)
+#define SIZEOF_PGD_HV_L1_SIZE(HPAGE_SHIFT)
 
 /*
  * The level-2 index is defined by the difference between the huge
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,8 +34,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * Note that the hypervisor docs use PTE for what we call pte_t, so
  * this nomenclature is somewhat confusing.
  */
-#define PTRS_PER_PTE (1 &amp;lt;&amp;lt; (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
-#define SIZEOF_PTE(PTRS_PER_PTE * sizeof(pte_t))
+#define PTRS_PER_PTE_HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
+#define PTE_INDEX(va)_HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT)
+#define SIZEOF_PTE_HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/tile/include/asm/pgtable_64.h b/arch/tile/include/asm/pgtable_64.h
index e105f3a..2492fa5 100644
--- a/arch/tile/include/asm/pgtable_64.h
+++ b/arch/tile/include/asm/pgtable_64.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -21,17 +21,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define PGDIR_SIZEHV_L1_SPAN
 #define PGDIR_MASK(~(PGDIR_SIZE-1))
 #define PTRS_PER_PGDHV_L0_ENTRIES
-#define SIZEOF_PGD(PTRS_PER_PGD * sizeof(pgd_t))
+#define PGD_INDEX(va)HV_L0_INDEX(va)
+#define SIZEOF_PGDHV_L0_SIZE
 
 /*
  * The level-1 index is defined by the huge page size.  A PMD is composed
  * of PTRS_PER_PMD pgd_t's and is the middle level of the page table.
  */
-#define PMD_SHIFTHV_LOG2_PAGE_SIZE_LARGE
-#define PMD_SIZEHV_PAGE_SIZE_LARGE
+#define PMD_SHIFTHPAGE_SHIFT
+#define PMD_SIZEHPAGE_SIZE
 #define PMD_MASK(~(PMD_SIZE-1))
-#define PTRS_PER_PMD(1 &amp;lt;&amp;lt; (PGDIR_SHIFT - PMD_SHIFT))
-#define SIZEOF_PMD(PTRS_PER_PMD * sizeof(pmd_t))
+#define PTRS_PER_PMD_HV_L1_ENTRIES(HPAGE_SHIFT)
+#define PMD_INDEX(va)_HV_L1_INDEX(va, HPAGE_SHIFT)
+#define SIZEOF_PMD_HV_L1_SIZE(HPAGE_SHIFT)
 
 /*
  * The level-2 index is defined by the difference between the huge
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -40,17 +42,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * Note that the hypervisor docs use PTE for what we call pte_t, so
  * this nomenclature is somewhat confusing.
  */
-#define PTRS_PER_PTE (1 &amp;lt;&amp;lt; (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL))
-#define SIZEOF_PTE(PTRS_PER_PTE * sizeof(pte_t))
+#define PTRS_PER_PTE_HV_L2_ENTRIES(HPAGE_SHIFT, PAGE_SHIFT)
+#define PTE_INDEX(va)_HV_L2_INDEX(va, HPAGE_SHIFT, PAGE_SHIFT)
+#define SIZEOF_PTE_HV_L2_SIZE(HPAGE_SHIFT, PAGE_SHIFT)
 
 /*
- * Align the vmalloc area to an L2 page table, and leave a guard page
- * at the beginning and end.  The vmalloc code also puts in an internal
+ * Align the vmalloc area to an L2 page table.  Omit guard pages at
+ * the beginning and end for simplicity (particularly in the per-cpu
+ * memory allocation code).  The vmalloc code puts in an internal
  * guard page between each allocation.
  */
 #define _VMALLOC_ENDHUGE_VMAP_BASE
-#define VMALLOC_END(_VMALLOC_END - PAGE_SIZE)
-#define VMALLOC_START(_VMALLOC_START + PAGE_SIZE)
+#define VMALLOC_END_VMALLOC_END
+#define VMALLOC_START_VMALLOC_START
 
 #define HUGE_VMAP_END(HUGE_VMAP_BASE + PGDIR_SIZE)
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -98,7 +102,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int pud_bad(pud_t pud)
  * A pud_t points to a pmd_t array.  Since we can have multiple per
  * page, we don't have a one-to-one mapping of pud_t's to pages.
  */
-#define pud_page(pud) pfn_to_page(HV_PTFN_TO_PFN(pud_ptfn(pud)))
+#define pud_page(pud) pfn_to_page(PFN_DOWN(HV_PTFN_TO_CPA(pud_ptfn(pud))))
 
 static inline unsigned long pud_index(unsigned long address)
 {
diff --git a/arch/tile/include/hv/drv_xgbe_intf.h b/arch/tile/include/hv/drv_xgbe_intf.h
index f13188a..2a20b26 100644
--- a/arch/tile/include/hv/drv_xgbe_intf.h
+++ b/arch/tile/include/hv/drv_xgbe_intf.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -460,7 +460,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; typedef void* lepp_comp_t;
  *  linux's "MAX_SKB_FRAGS", and presumably over-estimates by one, for
  *  our page size of exactly 65536.  We add one for a "body" fragment.
  */
-#define LEPP_MAX_FRAGS (65536 / HV_PAGE_SIZE_SMALL + 2 + 1)
+#define LEPP_MAX_FRAGS (65536 / HV_DEFAULT_PAGE_SIZE_SMALL + 2 + 1)
 
 /** Total number of bytes needed for an lepp_tso_cmd_t. */
 #define LEPP_TSO_CMD_SIZE(num_frags, header_size) \
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index df74223..f278717 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -17,8 +17,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  * The hypervisor's public API.
  */
 
-#ifndef _TILE_HV_H
-#define _TILE_HV_H
+#ifndef _HV_HV_H
+#define _HV_HV_H
 
 #include &amp;lt;arch/chip.h&amp;gt;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -42,25 +42,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  */
 #define HV_L1_SPAN (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_L1_SPAN)
 
-/** The log2 of the size of small pages, in bytes. This value should
- * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+/** The log2 of the initial size of small pages, in bytes.
+ * See HV_DEFAULT_PAGE_SIZE_SMALL.
  */
-#define HV_LOG2_PAGE_SIZE_SMALL 16
+#define HV_LOG2_DEFAULT_PAGE_SIZE_SMALL 16
 
-/** The size of small pages, in bytes. This value should be verified
+/** The initial size of small pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_SMALL).
+ * It may also be modified when installing a new context.
  */
-#define HV_PAGE_SIZE_SMALL (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_PAGE_SIZE_SMALL)
+#define HV_DEFAULT_PAGE_SIZE_SMALL \
+  (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_DEFAULT_PAGE_SIZE_SMALL)
 
-/** The log2 of the size of large pages, in bytes. This value should be
- * verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+/** The log2 of the initial size of large pages, in bytes.
+ * See HV_DEFAULT_PAGE_SIZE_LARGE.
  */
-#define HV_LOG2_PAGE_SIZE_LARGE 24
+#define HV_LOG2_DEFAULT_PAGE_SIZE_LARGE 24
 
-/** The size of large pages, in bytes. This value should be verified
+/** The initial size of large pages, in bytes. This value should be verified
  * at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_LARGE).
+ * It may also be modified when installing a new context.
  */
-#define HV_PAGE_SIZE_LARGE (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_PAGE_SIZE_LARGE)
+#define HV_DEFAULT_PAGE_SIZE_LARGE \
+  (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_DEFAULT_PAGE_SIZE_LARGE)
 
 /** The log2 of the granularity at which page tables must be aligned;
  *  in other words, the CPA for a page table must have this many zero
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -401,7 +405,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; typedef enum {
    *  that the temperature has hit an upper limit and is no longer being
    *  accurately tracked.
    */
-  HV_SYSCONF_BOARD_TEMP      = 6
+  HV_SYSCONF_BOARD_TEMP      = 6,
+
+  /** Legal page size bitmask for hv_install_context().
+   * For example, if 16KB and 64KB small pages are supported,
+   * it would return "HV_CTX_PG_SM_16K | HV_CTX_PG_SM_64K".
+   */
+  HV_SYSCONF_VALID_PAGE_SIZES = 7,
 
 } HV_SysconfQuery;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -654,6 +664,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void hv_set_rtc(HV_RTCTime time);
  *  new page table does not need to contain any mapping for the
  *  hv_install_context address itself.
  *
+ *  At most one HV_CTX_PG_SM_* flag may be specified in "flags";
+ *  if multiple flags are specified, HV_EINVAL is returned.
+ *  Specifying none of the flags results in using the default page size.
+ *  All cores participating in a given client must request the same
+ *  page size, or the results are undefined.
+ *
  * &amp;lt; at &amp;gt;param page_table Root of the page table.
  * &amp;lt; at &amp;gt;param access PTE providing info on how to read the page table.  This
  *   value must be consistent between multiple tiles sharing a page table,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -672,6 +688,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid,
 #define HV_CTX_DIRECTIO     0x1   /**&amp;lt; Direct I/O requests are accepted from
                                        PL0. */
 
+#define HV_CTX_PG_SM_4K     0x10  /**&amp;lt; Use 4K small pages, if available. */
+#define HV_CTX_PG_SM_16K    0x20  /**&amp;lt; Use 16K small pages, if available. */
+#define HV_CTX_PG_SM_64K    0x40  /**&amp;lt; Use 64K small pages, if available. */
+#define HV_CTX_PG_SM_MASK   0xf0  /**&amp;lt; Mask of all possible small pages. */
+
 #ifndef __ASSEMBLER__
 
 /** Value returned from hv_inquire_context(). */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1248,11 +1269,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; HV_Errno hv_set_command_line(HV_VirtAddr buf, int length);
  * with the existing priority pages) or "red/black" (if they don't).
  * The bitmask provides information on which parts of the cache
  * have been used for pinned pages so far on this tile; if (1 &amp;lt;&amp;lt; N)
- * appears in the bitmask, that indicates that a page has been marked
- * "priority" whose PFN equals N, mod 8.
+ * appears in the bitmask, that indicates that a 4KB region of the
+ * cache starting at (N * 4KB) is in use by a "priority" page.
+ * The portion of cache used by a particular page can be computed
+ * by taking the page's PA, modulo CHIP_L2_CACHE_SIZE(), and setting
+ * all the "4KB" bits corresponding to the actual page size.
  * &amp;lt; at &amp;gt;param bitmask A bitmap of priority page set values
  */
-void hv_set_caching(unsigned int bitmask);
+void hv_set_caching(unsigned long bitmask);
 
 
 /** Zero out a specified number of pages.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1884,15 +1908,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
                                               of word */
 #define HV_PTE_PTFN_BITS             29  /**&amp;lt; Number of bits in a PTFN */
 
-/** Position of the PFN field within the PTE (subset of the PTFN). */
-#define HV_PTE_INDEX_PFN (HV_PTE_INDEX_PTFN + (HV_LOG2_PAGE_SIZE_SMALL - \
-                                               HV_LOG2_PAGE_TABLE_ALIGN))
-
-/** Length of the PFN field within the PTE (subset of the PTFN). */
-#define HV_PTE_INDEX_PFN_BITS (HV_PTE_INDEX_PTFN_BITS - \
-                               (HV_LOG2_PAGE_SIZE_SMALL - \
-                                HV_LOG2_PAGE_TABLE_ALIGN))
-
 /*
  * Legal values for the PTE's mode field
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2245,40 +2260,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_set_mode(HV_PTE pte, unsigned int val)
  *
  * This field contains the upper bits of the CPA (client physical
  * address) of the target page; the complete CPA is this field with
- * HV_LOG2_PAGE_SIZE_SMALL zero bits appended to it.
+ * HV_LOG2_PAGE_TABLE_ALIGN zero bits appended to it.
  *
- * For PTEs in a level-1 page table where the Page bit is set, the
- * CPA must be aligned modulo the large page size.
- */
-static __inline unsigned int
-hv_pte_get_pfn(const HV_PTE pte)
-{
-  return pte.val &amp;gt;&amp;gt; HV_PTE_INDEX_PFN;
-}
-
-
-/** Set the page frame number into a PTE.  See hv_pte_get_pfn. */
-static __inline HV_PTE
-hv_pte_set_pfn(HV_PTE pte, unsigned int val)
-{
-  /*
-   * Note that the use of "PTFN" in the next line is intentional; we
-   * don't want any garbage lower bits left in that field.
-   */
-  pte.val &amp;amp;= ~(((1ULL &amp;lt;&amp;lt; HV_PTE_PTFN_BITS) - 1) &amp;lt;&amp;lt; HV_PTE_INDEX_PTFN);
-  pte.val |= (__hv64) val &amp;lt;&amp;lt; HV_PTE_INDEX_PFN;
-  return pte;
-}
-
-/** Get the page table frame number from the PTE.
- *
- * This field contains the upper bits of the CPA (client physical
- * address) of the target page table; the complete CPA is this field with
- * with HV_PAGE_TABLE_ALIGN zero bits appended to it.
- *
- * For PTEs in a level-1 page table when the Page bit is not set, the
- * CPA must be aligned modulo the sticter of HV_PAGE_TABLE_ALIGN and
- * the level-2 page table size.
+ * For all PTEs in the lowest-level page table, and for all PTEs with
+ * the Page bit set in all page tables, the CPA must be aligned modulo
+ * the relevant page size.
  */
 static __inline unsigned long
 hv_pte_get_ptfn(const HV_PTE pte)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2286,7 +2272,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_get_ptfn(const HV_PTE pte)
   return pte.val &amp;gt;&amp;gt; HV_PTE_INDEX_PTFN;
 }
 
-
 /** Set the page table frame number into a PTE.  See hv_pte_get_ptfn. */
 static __inline HV_PTE
 hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2296,6 +2281,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_set_ptfn(HV_PTE pte, unsigned long val)
   return pte;
 }
 
+/** Get the client physical address from the PTE.  See hv_pte_set_ptfn. */
+static __inline HV_PhysAddr
+hv_pte_get_pa(const HV_PTE pte)
+{
+  return (__hv64) hv_pte_get_ptfn(pte) &amp;lt;&amp;lt; HV_LOG2_PAGE_TABLE_ALIGN;
+}
+
+/** Set the client physical address into a PTE.  See hv_pte_get_ptfn. */
+static __inline HV_PTE
+hv_pte_set_pa(HV_PTE pte, HV_PhysAddr pa)
+{
+  return hv_pte_set_ptfn(pte, pa &amp;gt;&amp;gt; HV_LOG2_PAGE_TABLE_ALIGN);
+}
+
 
 /** Get the remote tile caching this page.
  *
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2331,28 +2330,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_set_lotar(HV_PTE pte, unsigned int val)
 
 #endif  /* !__ASSEMBLER__ */
 
-/** Converts a client physical address to a pfn. */
-#define HV_CPA_TO_PFN(p) ((p) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_SMALL)
-
-/** Converts a pfn to a client physical address. */
-#define HV_PFN_TO_CPA(p) (((HV_PhysAddr)(p)) &amp;lt;&amp;lt; HV_LOG2_PAGE_SIZE_SMALL)
-
 /** Converts a client physical address to a ptfn. */
 #define HV_CPA_TO_PTFN(p) ((p) &amp;gt;&amp;gt; HV_LOG2_PAGE_TABLE_ALIGN)
 
 /** Converts a ptfn to a client physical address. */
 #define HV_PTFN_TO_CPA(p) (((HV_PhysAddr)(p)) &amp;lt;&amp;lt; HV_LOG2_PAGE_TABLE_ALIGN)
 
-/** Converts a ptfn to a pfn. */
-#define HV_PTFN_TO_PFN(p) \
-  ((p) &amp;gt;&amp;gt; (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
-
-/** Converts a pfn to a ptfn. */
-#define HV_PFN_TO_PTFN(p) \
-  ((p) &amp;lt;&amp;lt; (HV_LOG2_PAGE_SIZE_SMALL - HV_LOG2_PAGE_TABLE_ALIGN))
-
 #if CHIP_VA_WIDTH() &amp;gt; 32
 
+/*
+ * Note that we currently do not allow customizing the page size
+ * of the L0 pages, but fix them at 4GB, so we do not use the
+ * "_HV_xxx" nomenclature for the L0 macros.
+ */
+
 /** Log number of HV_PTE entries in L0 page table */
 #define HV_LOG2_L0_ENTRIES (CHIP_VA_WIDTH() - HV_LOG2_L1_SPAN)
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2382,69 +2373,104 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_set_lotar(HV_PTE pte, unsigned int val)
 #endif /* CHIP_VA_WIDTH() &amp;gt; 32 */
 
 /** Log number of HV_PTE entries in L1 page table */
-#define HV_LOG2_L1_ENTRIES (HV_LOG2_L1_SPAN - HV_LOG2_PAGE_SIZE_LARGE)
+#define _HV_LOG2_L1_ENTRIES(log2_page_size_large) \
+  (HV_LOG2_L1_SPAN - log2_page_size_large)
 
 /** Number of HV_PTE entries in L1 page table */
-#define HV_L1_ENTRIES (1 &amp;lt;&amp;lt; HV_LOG2_L1_ENTRIES)
+#define _HV_L1_ENTRIES(log2_page_size_large) \
+  (1 &amp;lt;&amp;lt; _HV_LOG2_L1_ENTRIES(log2_page_size_large))
 
 /** Log size of L1 page table in bytes */
-#define HV_LOG2_L1_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L1_ENTRIES)
+#define _HV_LOG2_L1_SIZE(log2_page_size_large) \
+  (HV_LOG2_PTE_SIZE + _HV_LOG2_L1_ENTRIES(log2_page_size_large))
 
 /** Size of L1 page table in bytes */
-#define HV_L1_SIZE (1 &amp;lt;&amp;lt; HV_LOG2_L1_SIZE)
+#define _HV_L1_SIZE(log2_page_size_large) \
+  (1 &amp;lt;&amp;lt; _HV_LOG2_L1_SIZE(log2_page_size_large))
 
 /** Log number of HV_PTE entries in level-2 page table */
-#define HV_LOG2_L2_ENTRIES (HV_LOG2_PAGE_SIZE_LARGE - HV_LOG2_PAGE_SIZE_SMALL)
+#define _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \
+  (log2_page_size_large - log2_page_size_small)
 
 /** Number of HV_PTE entries in level-2 page table */
-#define HV_L2_ENTRIES (1 &amp;lt;&amp;lt; HV_LOG2_L2_ENTRIES)
+#define _HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) \
+  (1 &amp;lt;&amp;lt; _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small))
 
 /** Log size of level-2 page table in bytes */
-#define HV_LOG2_L2_SIZE (HV_LOG2_PTE_SIZE + HV_LOG2_L2_ENTRIES)
+#define _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small) \
+  (HV_LOG2_PTE_SIZE + \
+   _HV_LOG2_L2_ENTRIES(log2_page_size_large, log2_page_size_small))
 
 /** Size of level-2 page table in bytes */
-#define HV_L2_SIZE (1 &amp;lt;&amp;lt; HV_LOG2_L2_SIZE)
+#define _HV_L2_SIZE(log2_page_size_large, log2_page_size_small) \
+  (1 &amp;lt;&amp;lt; _HV_LOG2_L2_SIZE(log2_page_size_large, log2_page_size_small))
 
 #ifdef __ASSEMBLER__
 
 #if CHIP_VA_WIDTH() &amp;gt; 32
 
 /** Index in L1 for a specific VA */
-#define HV_L1_INDEX(va) \
-  (((va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_LARGE) &amp;amp; (HV_L1_ENTRIES - 1))
+#define _HV_L1_INDEX(va, log2_page_size_large) \
+  (((va) &amp;gt;&amp;gt; log2_page_size_large) &amp;amp; (_HV_L1_ENTRIES(log2_page_size_large) - 1))
 
 #else /* CHIP_VA_WIDTH() &amp;gt; 32 */
 
 /** Index in L1 for a specific VA */
-#define HV_L1_INDEX(va) \
-  (((va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_LARGE))
+#define _HV_L1_INDEX(va, log2_page_size_large) \
+  (((va) &amp;gt;&amp;gt; log2_page_size_large))
 
 #endif /* CHIP_VA_WIDTH() &amp;gt; 32 */
 
 /** Index in level-2 page table for a specific VA */
-#define HV_L2_INDEX(va) \
-  (((va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_SMALL) &amp;amp; (HV_L2_ENTRIES - 1))
+#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \
+  (((va) &amp;gt;&amp;gt; log2_page_size_small) &amp;amp; \
+   (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1))
 
 #else /* __ASSEMBLER __ */
 
 #if CHIP_VA_WIDTH() &amp;gt; 32
 
 /** Index in L1 for a specific VA */
-#define HV_L1_INDEX(va) \
-  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_LARGE) &amp;amp; (HV_L1_ENTRIES - 1))
+#define _HV_L1_INDEX(va, log2_page_size_large) \
+  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; log2_page_size_large) &amp;amp; \
+   (_HV_L1_ENTRIES(log2_page_size_large) - 1))
 
 #else /* CHIP_VA_WIDTH() &amp;gt; 32 */
 
 /** Index in L1 for a specific VA */
-#define HV_L1_INDEX(va) \
-  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_LARGE))
+#define _HV_L1_INDEX(va, log2_page_size_large) \
+  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; log2_page_size_large))
 
 #endif /* CHIP_VA_WIDTH() &amp;gt; 32 */
 
 /** Index in level-2 page table for a specific VA */
-#define HV_L2_INDEX(va) \
-  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; HV_LOG2_PAGE_SIZE_SMALL) &amp;amp; (HV_L2_ENTRIES - 1))
+#define _HV_L2_INDEX(va, log2_page_size_large, log2_page_size_small) \
+  (((HV_VirtAddr)(va) &amp;gt;&amp;gt; log2_page_size_small) &amp;amp; \
+   (_HV_L2_ENTRIES(log2_page_size_large, log2_page_size_small) - 1))
 
 #endif /* __ASSEMBLER __ */
 
-#endif /* _TILE_HV_H */
+/** Position of the PFN field within the PTE (subset of the PTFN). */
+#define _HV_PTE_INDEX_PFN(log2_page_size) \
+  (HV_PTE_INDEX_PTFN + (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
+
+/** Length of the PFN field within the PTE (subset of the PTFN). */
+#define _HV_PTE_INDEX_PFN_BITS(log2_page_size) \
+  (HV_PTE_INDEX_PTFN_BITS - (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
+
+/** Converts a client physical address to a pfn. */
+#define _HV_CPA_TO_PFN(p, log2_page_size) ((p) &amp;gt;&amp;gt; log2_page_size)
+
+/** Converts a pfn to a client physical address. */
+#define _HV_PFN_TO_CPA(p, log2_page_size) \
+  (((HV_PhysAddr)(p)) &amp;lt;&amp;lt; log2_page_size)
+
+/** Converts a ptfn to a pfn. */
+#define _HV_PTFN_TO_PFN(p, log2_page_size) \
+  ((p) &amp;gt;&amp;gt; (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
+
+/** Converts a pfn to a ptfn. */
+#define _HV_PFN_TO_PTFN(p, log2_page_size) \
+  ((p) &amp;lt;&amp;lt; (log2_page_size - HV_LOG2_PAGE_TABLE_ALIGN))
+
+#endif /* _HV_HV_H */
diff --git a/arch/tile/kernel/head_32.S b/arch/tile/kernel/head_32.S
index 1a39b7c..f71bfee 100644
--- a/arch/tile/kernel/head_32.S
+++ b/arch/tile/kernel/head_32.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -69,7 +69,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(_start)
 }
 {
   moveli lr, lo16(1f)
-  move r5, zero
+  moveli r5, CTX_PAGE_FLAG
 }
 {
   auli lr, lr, ha16(1f)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -141,11 +141,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(empty_zero_page)
 
 .macro PTE va, cpa, bits1, no_org=0
 .ifeq \no_org
-.org swapper_pg_dir + HV_L1_INDEX(\va) * HV_PTE_SIZE
+.org swapper_pg_dir + PGD_INDEX(\va) * HV_PTE_SIZE
 .endif
 .word HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED | \
       (HV_PTE_MODE_CACHE_NO_L3 &amp;lt;&amp;lt; HV_PTE_INDEX_MODE)
-.word (\bits1) | (HV_CPA_TO_PFN(\cpa) &amp;lt;&amp;lt; (HV_PTE_INDEX_PFN - 32))
+.word (\bits1) | (HV_CPA_TO_PTFN(\cpa) &amp;lt;&amp;lt; (HV_PTE_INDEX_PTFN - 32))
 .endm
 
 __PAGE_ALIGNED_DATA
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -166,7 +166,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(swapper_pg_dir)
 /* The true text VAs are mapped as VA = PA + MEM_SV_INTRPT */
 PTE MEM_SV_INTRPT, 0, (1 &amp;lt;&amp;lt; (HV_PTE_INDEX_READABLE - 32)) | \
       (1 &amp;lt;&amp;lt; (HV_PTE_INDEX_EXECUTABLE - 32))
-.org swapper_pg_dir + HV_L1_SIZE
+.org swapper_pg_dir + PGDIR_SIZE
 END(swapper_pg_dir)
 
 /*
diff --git a/arch/tile/kernel/head_64.S b/arch/tile/kernel/head_64.S
index 6bc3a93..f9a2734 100644
--- a/arch/tile/kernel/head_64.S
+++ b/arch/tile/kernel/head_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -114,7 +114,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(_start)
   shl16insli r0, r0, hw0(swapper_pg_dir - PAGE_OFFSET)
 }
 {
-  move r3, zero
+  moveli r3, CTX_PAGE_FLAG
   j hv_install_context
 }
 1:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -210,19 +210,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(empty_zero_page)
 .macro PTE cpa, bits1
 .quad HV_PTE_PAGE | HV_PTE_DIRTY | HV_PTE_PRESENT | HV_PTE_ACCESSED |\
       HV_PTE_GLOBAL | (HV_PTE_MODE_CACHE_NO_L3 &amp;lt;&amp;lt; HV_PTE_INDEX_MODE) |\
-      (\bits1) | (HV_CPA_TO_PFN(\cpa) &amp;lt;&amp;lt; HV_PTE_INDEX_PFN)
+      (\bits1) | (HV_CPA_TO_PTFN(\cpa) &amp;lt;&amp;lt; HV_PTE_INDEX_PTFN)
 .endm
 
 __PAGE_ALIGNED_DATA
 .align PAGE_SIZE
 ENTRY(swapper_pg_dir)
-.org swapper_pg_dir + HV_L0_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
+.org swapper_pg_dir + PGD_INDEX(PAGE_OFFSET) * HV_PTE_SIZE
 .Lsv_data_pmd:
 .quad 0  /* PTE temp_data_pmd - PAGE_OFFSET, 0 */
-.org swapper_pg_dir + HV_L0_INDEX(MEM_SV_START) * HV_PTE_SIZE
+.org swapper_pg_dir + PGD_INDEX(MEM_SV_START) * HV_PTE_SIZE
 .Lsv_code_pmd:
 .quad 0  /* PTE temp_code_pmd - PAGE_OFFSET, 0 */
-.org swapper_pg_dir + HV_L0_SIZE
+.org swapper_pg_dir + SIZEOF_PGD
 END(swapper_pg_dir)
 
 .align HV_PAGE_TABLE_ALIGN
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -233,11 +233,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(temp_data_pmd)
  * permissions later.
  */
 .set addr, 0
-.rept HV_L1_ENTRIES
+.rept PTRS_PER_PMD
 PTE addr, HV_PTE_READABLE | HV_PTE_WRITABLE
-.set addr, addr + HV_PAGE_SIZE_LARGE
+.set addr, addr + HPAGE_SIZE
 .endr
-.org temp_data_pmd + HV_L1_SIZE
+.org temp_data_pmd + SIZEOF_PMD
 END(temp_data_pmd)
 
 .align HV_PAGE_TABLE_ALIGN
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -248,11 +248,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; ENTRY(temp_code_pmd)
  * permissions later.
  */
 .set addr, 0
-.rept HV_L1_ENTRIES
+.rept PTRS_PER_PMD
 PTE addr, HV_PTE_READABLE | HV_PTE_EXECUTABLE
-.set addr, addr + HV_PAGE_SIZE_LARGE
+.set addr, addr + HPAGE_SIZE
 .endr
-.org temp_code_pmd + HV_L1_SIZE
+.org temp_code_pmd + SIZEOF_PMD
 END(temp_code_pmd)
 
 /*
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
index 6255f2e..b0fa37c 100644
--- a/arch/tile/kernel/machine_kexec.c
+++ b/arch/tile/kernel/machine_kexec.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -251,6 +251,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void setup_quasi_va_is_pa(void)
 void machine_kexec(struct kimage *image)
 {
 void *reboot_code_buffer;
+pte_t *ptep;
 void (*rnk)(unsigned long, void *, unsigned long)
 __noreturn;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -266,8 +267,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void machine_kexec(struct kimage *image)
  */
 homecache_change_page_home(image-&amp;gt;control_code_page, 0,
    smp_processor_id());
-reboot_code_buffer = vmap(&amp;amp;image-&amp;gt;control_code_page, 1, 0,
-  __pgprot(_PAGE_KERNEL | _PAGE_EXECUTABLE));
+reboot_code_buffer = page_address(image-&amp;gt;control_code_page);
+BUG_ON(reboot_code_buffer == NULL);
+ptep = virt_to_pte(NULL, (unsigned long)reboot_code_buffer);
+__set_pte(ptep, pte_mkexec(*ptep));
 memcpy(reboot_code_buffer, relocate_new_kernel,
        relocate_new_kernel_size);
 __flush_icache_range(
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index bff23f4..32948e2 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1396,13 +1396,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init setup_per_cpu_areas(void)
 for (i = 0; i &amp;lt; size; i += PAGE_SIZE, ++pfn, ++pg) {
 
 /* Update the vmalloc mapping and page home. */
-pte_t *ptep =
-virt_to_pte(NULL, (unsigned long)ptr + i);
+unsigned long addr = (unsigned long)ptr + i;
+pte_t *ptep = virt_to_pte(NULL, addr);
 pte_t pte = *ptep;
 BUG_ON(pfn != pte_pfn(pte));
 pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_TILE_L3);
 pte = set_remote_cache_cpu(pte, cpu);
-set_pte(ptep, pte);
+set_pte_at(&amp;amp;init_mm, addr, ptep, pte);
 
 /* Update the lowmem mapping for consistency. */
 lowmem_va = (unsigned long)pfn_to_kaddr(pfn);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1415,7 +1415,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init setup_per_cpu_areas(void)
 BUG_ON(pte_huge(*ptep));
 }
 BUG_ON(pfn != pte_pfn(*ptep));
-set_pte(ptep, pte);
+set_pte_at(&amp;amp;init_mm, lowmem_va, ptep, pte);
 }
 }
 
diff --git a/arch/tile/kernel/smp.c b/arch/tile/kernel/smp.c
index 91da0f7..cbc73a8 100644
--- a/arch/tile/kernel/smp.c
+++ b/arch/tile/kernel/smp.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -203,7 +203,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init ipi_init(void)
 if (hv_get_ipi_pte(tile, KERNEL_PL, &amp;amp;pte) != 0)
 panic("Failed to initialize IPI for cpu %d\n", cpu);
 
-offset = hv_pte_get_pfn(pte) &amp;lt;&amp;lt; PAGE_SHIFT;
+offset = PFN_PHYS(pte_pfn(pte));
 ipi_mappings[cpu] = ioremap_prot(offset, PAGE_SIZE, pte);
 }
 #endif
diff --git a/arch/tile/lib/memcpy_tile64.c b/arch/tile/lib/memcpy_tile64.c
index b2fe15e..3bc4b4e 100644
--- a/arch/tile/lib/memcpy_tile64.c
+++ b/arch/tile/lib/memcpy_tile64.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -160,7 +160,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; retry_source:
 break;
 if (get_remote_cache_cpu(src_pte) == smp_processor_id())
 break;
-src_page = pfn_to_page(hv_pte_get_pfn(src_pte));
+src_page = pfn_to_page(pte_pfn(src_pte));
 get_page(src_page);
 if (pte_val(src_pte) != pte_val(*src_ptep)) {
 put_page(src_page);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -168,7 +168,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; retry_source:
 }
 if (pte_huge(src_pte)) {
 /* Adjust the PTE to correspond to a small page */
-int pfn = hv_pte_get_pfn(src_pte);
+int pfn = pte_pfn(src_pte);
 pfn += (((unsigned long)source &amp;amp; (HPAGE_SIZE-1))
 &amp;gt;&amp;gt; PAGE_SHIFT);
 src_pte = pfn_pte(pfn, src_pte);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -188,7 +188,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; retry_dest:
 put_page(src_page);
 break;
 }
-dst_page = pfn_to_page(hv_pte_get_pfn(dst_pte));
+dst_page = pfn_to_page(pte_pfn(dst_pte));
 if (dst_page == src_page) {
 /*
  * Source and dest are on the same page; this
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -206,7 +206,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; retry_dest:
 }
 if (pte_huge(dst_pte)) {
 /* Adjust the PTE to correspond to a small page */
-int pfn = hv_pte_get_pfn(dst_pte);
+int pfn = pte_pfn(dst_pte);
 pfn += (((unsigned long)dest &amp;amp; (HPAGE_SIZE-1))
 &amp;gt;&amp;gt; PAGE_SHIFT);
 dst_pte = pfn_pte(pfn, dst_pte);
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 1e46335..c04fbfd 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -82,7 +82,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int num_l2_ptes[MAX_NUMNODES];
 
 static void init_prealloc_ptes(int node, int pages)
 {
-BUG_ON(pages &amp;amp; (HV_L2_ENTRIES-1));
+BUG_ON(pages &amp;amp; (PTRS_PER_PTE - 1));
 if (pages) {
 num_l2_ptes[node] = pages;
 l2_ptes[node] = __alloc_bootmem(pages * sizeof(pte_t),
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -131,14 +131,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init assign_pte(pmd_t *pmd, pte_t *page_table)
 
 #ifdef __tilegx__
 
-#if HV_L1_SIZE != HV_L2_SIZE
-# error Rework assumption that L1 and L2 page tables are same size.
-#endif
-
-/* Since pmd_t arrays and pte_t arrays are the same size, just use casts. */
 static inline pmd_t *alloc_pmd(void)
 {
-return (pmd_t *)alloc_pte();
+return __alloc_bootmem(L1_KERNEL_PGTABLE_SIZE, HV_PAGE_TABLE_ALIGN, 0);
 }
 
 static inline void assign_pmd(pud_t *pud, pmd_t *pmd)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -811,7 +806,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init paging_init(void)
  * changing init_mm once we get up and running, and there's no
  * need for e.g. vmalloc_sync_all().
  */
-BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END));
+BUILD_BUG_ON(pgd_index(VMALLOC_START) != pgd_index(VMALLOC_END - 1));
 pud = pud_offset(pgd_base + pgd_index(VMALLOC_START), VMALLOC_START);
 assign_pmd(pud, alloc_pmd());
 #endif
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 2410aa8..3d70743 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -289,13 +289,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void pgd_free(struct mm_struct *mm, pgd_t *pgd)
 
 #define L2_USER_PGTABLE_PAGES (1 &amp;lt;&amp;lt; L2_USER_PGTABLE_ORDER)
 
-struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
+struct page *pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
+       int order)
 {
 gfp_t flags = GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO;
 struct page *p;
-#if L2_USER_PGTABLE_ORDER &amp;gt; 0
 int i;
-#endif
 
 #ifdef CONFIG_HIGHPTE
 flags |= __GFP_HIGHMEM;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -305,17 +304,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
 if (p == NULL)
 return NULL;
 
-#if L2_USER_PGTABLE_ORDER &amp;gt; 0
 /*
  * Make every page have a page_count() of one, not just the first.
  * We don't use __GFP_COMP since it doesn't look like it works
  * correctly with tlb_remove_page().
  */
-for (i = 1; i &amp;lt; L2_USER_PGTABLE_PAGES; ++i) {
+for (i = 1; i &amp;lt; order; ++i) {
 init_page_count(p+i);
 inc_zone_page_state(p+i, NR_PAGETABLE);
 }
-#endif
 
 pgtable_page_ctor(p);
 return p;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -326,28 +323,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct page *pte_alloc_one(struct mm_struct *mm, unsigned long address)
  * process).  We have to correct whatever pte_alloc_one() did before
  * returning the pages to the allocator.
  */
-void pte_free(struct mm_struct *mm, struct page *p)
+void pgtable_free(struct mm_struct *mm, struct page *p, int order)
 {
 int i;
 
 pgtable_page_dtor(p);
 __free_page(p);
 
-for (i = 1; i &amp;lt; L2_USER_PGTABLE_PAGES; ++i) {
+for (i = 1; i &amp;lt; order; ++i) {
 __free_page(p+i);
 dec_zone_page_state(p+i, NR_PAGETABLE);
 }
 }
 
-void __pte_free_tlb(struct mmu_gather *tlb, struct page *pte,
-    unsigned long address)
+void __pgtable_free_tlb(struct mmu_gather *tlb, struct page *pte,
+unsigned long address, int order)
 {
 int i;
 
 pgtable_page_dtor(pte);
 tlb_remove_page(tlb, pte);
 
-for (i = 1; i &amp;lt; L2_USER_PGTABLE_PAGES; ++i) {
+for (i = 1; i &amp;lt; order; ++i) {
 tlb_remove_page(tlb, pte + i);
 dec_zone_page_state(pte + i, NR_PAGETABLE);
 }
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -490,7 +487,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void set_pte(pte_t *ptep, pte_t pte)
 /* Can this mm load a PTE with cached_priority set? */
 static inline int mm_is_priority_cached(struct mm_struct *mm)
 {
-return mm-&amp;gt;context.priority_cached;
+return mm-&amp;gt;context.priority_cached != 0;
 }
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -500,8 +497,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int mm_is_priority_cached(struct mm_struct *mm)
 void start_mm_caching(struct mm_struct *mm)
 {
 if (!mm_is_priority_cached(mm)) {
-mm-&amp;gt;context.priority_cached = -1U;
-hv_set_caching(-1U);
+mm-&amp;gt;context.priority_cached = -1UL;
+hv_set_caching(-1UL);
 }
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -516,7 +513,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void start_mm_caching(struct mm_struct *mm)
  * Presumably we'll come back later and have more luck and clear
  * the value then; for now we'll just keep the cache marked for priority.
  */
-static unsigned int update_priority_cached(struct mm_struct *mm)
+static unsigned long update_priority_cached(struct mm_struct *mm)
 {
 if (mm-&amp;gt;context.priority_cached &amp;amp;&amp;amp; down_write_trylock(&amp;amp;mm-&amp;gt;mmap_sem)) {
 struct vm_area_struct *vm;
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323187">
    <title>arch/tile: fix hardwall for tilegx and generalize for idn and ipi</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323187</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=b8ace0833feb308b1cb69d8b33ab08e0602dd2d2
Commit:     b8ace0833feb308b1cb69d8b33ab08e0602dd2d2
Parent:     621b19551507c8fd9d721f4038509c5bb155a983
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Fri Mar 30 16:01:48 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:27 2012 -0400

    arch/tile: fix hardwall for tilegx and generalize for idn and ipi
    
    The hardwall drain code was not properly implemented for tilegx,
    just tilepro, so you couldn't reliably restart an application that
    made use of the udn.
    
    In addition, the code was only applicable to the udn (user dynamic
    network).  On tilegx there is a second user network that is available
    (the "idn"), and there is support for having I/O shims deliver
    user-level interrupts to applications ("ipi") which functions in a
    very similar way to the inter-core permissions used for udn/idn.
    So this change also generalizes the code from supporting just the udn
    to supports udn/idn/ipi on tilegx.
    
    By default we now use /dev/hardwall/{udn,idn,ipi} with separate
    minor numbers for the three devices.
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/arch/spr_def_32.h |   56 +++
 arch/tile/include/arch/spr_def_64.h |   43 ++
 arch/tile/include/asm/hardwall.h    |   18 +-
 arch/tile/include/asm/processor.h   |   17 +-
 arch/tile/include/asm/setup.h       |   10 +-
 arch/tile/kernel/hardwall.c         |  754 +++++++++++++++++++++++------------
 arch/tile/kernel/intvec_64.S        |    2 +-
 arch/tile/kernel/process.c          |   16 +-
 8 files changed, 636 insertions(+), 280 deletions(-)

diff --git a/arch/tile/include/arch/spr_def_32.h b/arch/tile/include/arch/spr_def_32.h
index bbc1f4c..78bbce2 100644
--- a/arch/tile/include/arch/spr_def_32.h
+++ b/arch/tile/include/arch/spr_def_32.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -65,6 +65,31 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
 #define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
 #define SPR_FAIL 0x4e09
+#define SPR_IDN_AVAIL_EN 0x3e05
+#define SPR_IDN_CA_DATA 0x0b00
+#define SPR_IDN_DATA_AVAIL 0x0b03
+#define SPR_IDN_DEADLOCK_TIMEOUT 0x3406
+#define SPR_IDN_DEMUX_CA_COUNT 0x0a05
+#define SPR_IDN_DEMUX_COUNT_0 0x0a06
+#define SPR_IDN_DEMUX_COUNT_1 0x0a07
+#define SPR_IDN_DEMUX_CTL 0x0a08
+#define SPR_IDN_DEMUX_QUEUE_SEL 0x0a0a
+#define SPR_IDN_DEMUX_STATUS 0x0a0b
+#define SPR_IDN_DEMUX_WRITE_FIFO 0x0a0c
+#define SPR_IDN_DIRECTION_PROTECT 0x2e05
+#define SPR_IDN_PENDING 0x0a0e
+#define SPR_IDN_REFILL_EN 0x0e05
+#define SPR_IDN_SP_FIFO_DATA 0x0a0f
+#define SPR_IDN_SP_FIFO_SEL 0x0a10
+#define SPR_IDN_SP_FREEZE 0x0a11
+#define SPR_IDN_SP_FREEZE__SP_FRZ_MASK  0x1
+#define SPR_IDN_SP_FREEZE__DEMUX_FRZ_MASK  0x2
+#define SPR_IDN_SP_FREEZE__NON_DEST_EXT_MASK  0x4
+#define SPR_IDN_SP_STATE 0x0a12
+#define SPR_IDN_TAG_0 0x0a13
+#define SPR_IDN_TAG_1 0x0a14
+#define SPR_IDN_TAG_VALID 0x0a15
+#define SPR_IDN_TILE_COORD 0x0a16
 #define SPR_INTCTRL_0_STATUS 0x4a07
 #define SPR_INTCTRL_1_STATUS 0x4807
 #define SPR_INTCTRL_2_STATUS 0x4607
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -87,12 +112,36 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_INTERRUPT_MASK_SET_1_1 0x480e
 #define SPR_INTERRUPT_MASK_SET_2_0 0x460c
 #define SPR_INTERRUPT_MASK_SET_2_1 0x460d
+#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x6000
+#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x6001
+#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x6002
 #define SPR_MPL_DMA_CPL_SET_0 0x5800
 #define SPR_MPL_DMA_CPL_SET_1 0x5801
 #define SPR_MPL_DMA_CPL_SET_2 0x5802
 #define SPR_MPL_DMA_NOTIFY_SET_0 0x3800
 #define SPR_MPL_DMA_NOTIFY_SET_1 0x3801
 #define SPR_MPL_DMA_NOTIFY_SET_2 0x3802
+#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00
+#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01
+#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02
+#define SPR_MPL_IDN_AVAIL_SET_0 0x3e00
+#define SPR_MPL_IDN_AVAIL_SET_1 0x3e01
+#define SPR_MPL_IDN_AVAIL_SET_2 0x3e02
+#define SPR_MPL_IDN_CA_SET_0 0x3a00
+#define SPR_MPL_IDN_CA_SET_1 0x3a01
+#define SPR_MPL_IDN_CA_SET_2 0x3a02
+#define SPR_MPL_IDN_COMPLETE_SET_0 0x1200
+#define SPR_MPL_IDN_COMPLETE_SET_1 0x1201
+#define SPR_MPL_IDN_COMPLETE_SET_2 0x1202
+#define SPR_MPL_IDN_FIREWALL_SET_0 0x2e00
+#define SPR_MPL_IDN_FIREWALL_SET_1 0x2e01
+#define SPR_MPL_IDN_FIREWALL_SET_2 0x2e02
+#define SPR_MPL_IDN_REFILL_SET_0 0x0e00
+#define SPR_MPL_IDN_REFILL_SET_1 0x0e01
+#define SPR_MPL_IDN_REFILL_SET_2 0x0e02
+#define SPR_MPL_IDN_TIMER_SET_0 0x3400
+#define SPR_MPL_IDN_TIMER_SET_1 0x3401
+#define SPR_MPL_IDN_TIMER_SET_2 0x3402
 #define SPR_MPL_INTCTRL_0_SET_0 0x4a00
 #define SPR_MPL_INTCTRL_0_SET_1 0x4a01
 #define SPR_MPL_INTCTRL_0_SET_2 0x4a02
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -102,6 +151,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_MPL_INTCTRL_2_SET_0 0x4600
 #define SPR_MPL_INTCTRL_2_SET_1 0x4601
 #define SPR_MPL_INTCTRL_2_SET_2 0x4602
+#define SPR_MPL_PERF_COUNT_SET_0 0x4200
+#define SPR_MPL_PERF_COUNT_SET_1 0x4201
+#define SPR_MPL_PERF_COUNT_SET_2 0x4202
 #define SPR_MPL_SN_ACCESS_SET_0 0x0800
 #define SPR_MPL_SN_ACCESS_SET_1 0x0801
 #define SPR_MPL_SN_ACCESS_SET_2 0x0802
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -181,6 +233,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_UDN_DEMUX_STATUS 0x0c0d
 #define SPR_UDN_DEMUX_WRITE_FIFO 0x0c0e
 #define SPR_UDN_DIRECTION_PROTECT 0x3005
+#define SPR_UDN_PENDING 0x0c10
 #define SPR_UDN_REFILL_EN 0x1005
 #define SPR_UDN_SP_FIFO_DATA 0x0c11
 #define SPR_UDN_SP_FIFO_SEL 0x0c12
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -195,6 +248,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_UDN_TAG_3 0x0c18
 #define SPR_UDN_TAG_VALID 0x0c19
 #define SPR_UDN_TILE_COORD 0x0c1a
+#define SPR_WATCH_CTL 0x4209
+#define SPR_WATCH_MASK 0x420a
+#define SPR_WATCH_VAL 0x420b
 
 #endif /* !defined(__ARCH_SPR_DEF_H__) */
 
diff --git a/arch/tile/include/arch/spr_def_64.h b/arch/tile/include/arch/spr_def_64.h
index cd3e5f9..0da86fa 100644
--- a/arch/tile/include/arch/spr_def_64.h
+++ b/arch/tile/include/arch/spr_def_64.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -52,6 +52,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_EX_CONTEXT_2_1__ICS_RMASK 0x1
 #define SPR_EX_CONTEXT_2_1__ICS_MASK  0x4
 #define SPR_FAIL 0x2707
+#define SPR_IDN_AVAIL_EN 0x1a05
+#define SPR_IDN_DATA_AVAIL 0x0a80
+#define SPR_IDN_DEADLOCK_TIMEOUT 0x1806
+#define SPR_IDN_DEMUX_COUNT_0 0x0a05
+#define SPR_IDN_DEMUX_COUNT_1 0x0a06
+#define SPR_IDN_DIRECTION_PROTECT 0x1405
+#define SPR_IDN_PENDING 0x0a08
 #define SPR_ILL_TRANS_REASON__I_STREAM_VA_RMASK 0x1
 #define SPR_INTCTRL_0_STATUS 0x2505
 #define SPR_INTCTRL_1_STATUS 0x2405
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -88,9 +95,27 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_IPI_MASK_SET_0 0x1f0a
 #define SPR_IPI_MASK_SET_1 0x1e0a
 #define SPR_IPI_MASK_SET_2 0x1d0a
+#define SPR_MPL_AUX_PERF_COUNT_SET_0 0x2100
+#define SPR_MPL_AUX_PERF_COUNT_SET_1 0x2101
+#define SPR_MPL_AUX_PERF_COUNT_SET_2 0x2102
 #define SPR_MPL_AUX_TILE_TIMER_SET_0 0x1700
 #define SPR_MPL_AUX_TILE_TIMER_SET_1 0x1701
 #define SPR_MPL_AUX_TILE_TIMER_SET_2 0x1702
+#define SPR_MPL_IDN_ACCESS_SET_0 0x0a00
+#define SPR_MPL_IDN_ACCESS_SET_1 0x0a01
+#define SPR_MPL_IDN_ACCESS_SET_2 0x0a02
+#define SPR_MPL_IDN_AVAIL_SET_0 0x1a00
+#define SPR_MPL_IDN_AVAIL_SET_1 0x1a01
+#define SPR_MPL_IDN_AVAIL_SET_2 0x1a02
+#define SPR_MPL_IDN_COMPLETE_SET_0 0x0500
+#define SPR_MPL_IDN_COMPLETE_SET_1 0x0501
+#define SPR_MPL_IDN_COMPLETE_SET_2 0x0502
+#define SPR_MPL_IDN_FIREWALL_SET_0 0x1400
+#define SPR_MPL_IDN_FIREWALL_SET_1 0x1401
+#define SPR_MPL_IDN_FIREWALL_SET_2 0x1402
+#define SPR_MPL_IDN_TIMER_SET_0 0x1800
+#define SPR_MPL_IDN_TIMER_SET_1 0x1801
+#define SPR_MPL_IDN_TIMER_SET_2 0x1802
 #define SPR_MPL_INTCTRL_0_SET_0 0x2500
 #define SPR_MPL_INTCTRL_0_SET_1 0x2501
 #define SPR_MPL_INTCTRL_0_SET_2 0x2502
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -100,6 +125,21 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_MPL_INTCTRL_2_SET_0 0x2300
 #define SPR_MPL_INTCTRL_2_SET_1 0x2301
 #define SPR_MPL_INTCTRL_2_SET_2 0x2302
+#define SPR_MPL_IPI_0 0x1f04
+#define SPR_MPL_IPI_0_SET_0 0x1f00
+#define SPR_MPL_IPI_0_SET_1 0x1f01
+#define SPR_MPL_IPI_0_SET_2 0x1f02
+#define SPR_MPL_IPI_1 0x1e04
+#define SPR_MPL_IPI_1_SET_0 0x1e00
+#define SPR_MPL_IPI_1_SET_1 0x1e01
+#define SPR_MPL_IPI_1_SET_2 0x1e02
+#define SPR_MPL_IPI_2 0x1d04
+#define SPR_MPL_IPI_2_SET_0 0x1d00
+#define SPR_MPL_IPI_2_SET_1 0x1d01
+#define SPR_MPL_IPI_2_SET_2 0x1d02
+#define SPR_MPL_PERF_COUNT_SET_0 0x2000
+#define SPR_MPL_PERF_COUNT_SET_1 0x2001
+#define SPR_MPL_PERF_COUNT_SET_2 0x2002
 #define SPR_MPL_UDN_ACCESS_SET_0 0x0b00
 #define SPR_MPL_UDN_ACCESS_SET_1 0x0b01
 #define SPR_MPL_UDN_ACCESS_SET_2 0x0b02
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -167,6 +207,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define SPR_UDN_DEMUX_COUNT_2 0x0b07
 #define SPR_UDN_DEMUX_COUNT_3 0x0b08
 #define SPR_UDN_DIRECTION_PROTECT 0x1505
+#define SPR_UDN_PENDING 0x0b0a
+#define SPR_WATCH_MASK 0x200a
+#define SPR_WATCH_VAL 0x200b
 
 #endif /* !defined(__ARCH_SPR_DEF_H__) */
 
diff --git a/arch/tile/include/asm/hardwall.h b/arch/tile/include/asm/hardwall.h
index 2ac4228..47514a5 100644
--- a/arch/tile/include/asm/hardwall.h
+++ b/arch/tile/include/asm/hardwall.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -11,12 +11,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  *   NON INFRINGEMENT.  See the GNU General Public License for
  *   more details.
  *
- * Provide methods for the HARDWALL_FILE for accessing the UDN.
+ * Provide methods for access control of per-cpu resources like
+ * UDN, IDN, or IPI.
  */
 
 #ifndef _ASM_TILE_HARDWALL_H
 #define _ASM_TILE_HARDWALL_H
 
+#include &amp;lt;arch/chip.h&amp;gt;
 #include &amp;lt;linux/ioctl.h&amp;gt;
 
 #define HARDWALL_IOCTL_BASE 0xa2
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,8 +26,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /*
  * The HARDWALL_CREATE() ioctl is a macro with a "size" argument.
  * The resulting ioctl value is passed to the kernel in conjunction
- * with a pointer to a little-endian bitmask of cpus, which must be
- * physically in a rectangular configuration on the chip.
+ * with a pointer to a standard kernel bitmask of cpus.
+ * For network resources (UDN or IDN) the bitmask must physically
+ * represent a rectangular configuration on the chip.
  * The "size" is the number of bytes of cpu mask data.
  */
 #define _HARDWALL_CREATE 1
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -44,13 +47,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define HARDWALL_GET_ID \
  _IO(HARDWALL_IOCTL_BASE, _HARDWALL_GET_ID)
 
-#ifndef __KERNEL__
-
-/* This is the canonical name expected by userspace. */
-#define HARDWALL_FILE "/dev/hardwall"
-
-#else
-
+#ifdef __KERNEL__
 /* /proc hooks for hardwall. */
 struct proc_dir_entry;
 #ifdef CONFIG_HARDWALL
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -59,7 +56,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int proc_pid_hardwall(struct task_struct *task, char *buffer);
 #else
 static inline void proc_tile_hardwall_init(struct proc_dir_entry *root) {}
 #endif
-
 #endif
 
 #endif /* _ASM_TILE_HARDWALL_H */
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h
index 34c1e01..e85a9af 100644
--- a/arch/tile/include/asm/processor.h
+++ b/arch/tile/include/asm/processor.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -76,6 +76,17 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct async_tlb {
 
 #ifdef CONFIG_HARDWALL
 struct hardwall_info;
+struct hardwall_task {
+/* Which hardwall is this task tied to? (or NULL if none) */
+struct hardwall_info *info;
+/* Chains this task into the list at info-&amp;gt;task_head. */
+struct list_head list;
+};
+#ifdef __tilepro__
+#define HARDWALL_TYPES 1   /* udn */
+#else
+#define HARDWALL_TYPES 3   /* udn, idn, and ipi */
+#endif
 #endif
 
 struct thread_struct {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -116,10 +127,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct thread_struct {
 unsigned long dstream_pf;
 #endif
 #ifdef CONFIG_HARDWALL
-/* Is this task tied to an activated hardwall? */
-struct hardwall_info *hardwall;
-/* Chains this task into the list at hardwall-&amp;gt;list. */
-struct list_head hardwall_list;
+/* Hardwall information for various resources. */
+struct hardwall_task hardwall[HARDWALL_TYPES];
 #endif
 #if CHIP_HAS_TILE_DMA()
 /* Async DMA TLB fault information */
diff --git a/arch/tile/include/asm/setup.h b/arch/tile/include/asm/setup.h
index e58613e..c67eb70 100644
--- a/arch/tile/include/asm/setup.h
+++ b/arch/tile/include/asm/setup.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -41,15 +41,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void restrict_dma_mpls(void);
 #ifdef CONFIG_HARDWALL
 /* User-level network management functions */
 void reset_network_state(void);
-void grant_network_mpls(void);
-void restrict_network_mpls(void);
 struct task_struct;
-int hardwall_deactivate(struct task_struct *task);
+void hardwall_switch_tasks(struct task_struct *prev, struct task_struct *next);
+void hardwall_deactivate_all(struct task_struct *task);
+int hardwall_ipi_valid(int cpu);
 
 /* Hook hardwall code into changes in affinity. */
 #define arch_set_cpus_allowed(p, new_mask) do { \
-if (p-&amp;gt;thread.hardwall &amp;amp;&amp;amp; !cpumask_equal(&amp;amp;p-&amp;gt;cpus_allowed, new_mask)) \
-hardwall_deactivate(p); \
+if (!cpumask_equal(&amp;amp;p-&amp;gt;cpus_allowed, new_mask)) \
+hardwall_deactivate_all(p); \
 } while (0)
 #endif
 
diff --git a/arch/tile/kernel/hardwall.c b/arch/tile/kernel/hardwall.c
index 8c41891..20273ee 100644
--- a/arch/tile/kernel/hardwall.c
+++ b/arch/tile/kernel/hardwall.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,59 +33,157 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 
 /*
- * This data structure tracks the rectangle data, etc., associated
- * one-to-one with a "struct file *" from opening HARDWALL_FILE.
+ * Implement a per-cpu "hardwall" resource class such as UDN or IPI.
+ * We use "hardwall" nomenclature throughout for historical reasons.
+ * The lock here controls access to the list data structure as well as
+ * to the items on the list.
+ */
+struct hardwall_type {
+int index;
+int is_xdn;
+int is_idn;
+int disabled;
+const char *name;
+struct list_head list;
+spinlock_t lock;
+struct proc_dir_entry *proc_dir;
+};
+
+enum hardwall_index {
+HARDWALL_UDN = 0,
+#ifndef __tilepro__
+HARDWALL_IDN = 1,
+HARDWALL_IPI = 2,
+#endif
+_HARDWALL_TYPES
+};
+
+static struct hardwall_type hardwall_types[] = {
+{  /* user-space access to UDN */
+0,
+1,
+0,
+0,
+"udn",
+LIST_HEAD_INIT(hardwall_types[HARDWALL_UDN].list),
+__SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_UDN].lock),
+NULL
+},
+#ifndef __tilepro__
+{  /* user-space access to IDN */
+1,
+1,
+1,
+1,  /* disabled pending hypervisor support */
+"idn",
+LIST_HEAD_INIT(hardwall_types[HARDWALL_IDN].list),
+__SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IDN].lock),
+NULL
+},
+{  /* access to user-space IPI */
+2,
+0,
+0,
+0,
+"ipi",
+LIST_HEAD_INIT(hardwall_types[HARDWALL_IPI].list),
+__SPIN_LOCK_INITIALIZER(hardwall_types[HARDWALL_IPI].lock),
+NULL
+},
+#endif
+};
+
+/*
+ * This data structure tracks the cpu data, etc., associated
+ * one-to-one with a "struct file *" from opening a hardwall device file.
  * Note that the file's private data points back to this structure.
  */
 struct hardwall_info {
-struct list_head list;             /* "rectangles" list */
+struct list_head list;             /* for hardwall_types.list */
 struct list_head task_head;        /* head of tasks in this hardwall */
-struct cpumask cpumask;            /* cpus in the rectangle */
+struct hardwall_type *type;        /* type of this resource */
+struct cpumask cpumask;            /* cpus reserved */
+int id;                            /* integer id for this hardwall */
+int teardown_in_progress;          /* are we tearing this one down? */
+
+/* Remaining fields only valid for user-network resources. */
 int ulhc_x;                        /* upper left hand corner x coord */
 int ulhc_y;                        /* upper left hand corner y coord */
 int width;                         /* rectangle width */
 int height;                        /* rectangle height */
-int id;                            /* integer id for this hardwall */
-int teardown_in_progress;          /* are we tearing this one down? */
+#if CHIP_HAS_REV1_XDN()
+atomic_t xdn_pending_count;        /* cores in phase 1 of drain */
+#endif
 };
 
-/* Currently allocated hardwall rectangles */
-static LIST_HEAD(rectangles);
 
 /* /proc/tile/hardwall */
 static struct proc_dir_entry *hardwall_proc_dir;
 
 /* Functions to manage files in /proc/tile/hardwall. */
-static void hardwall_add_proc(struct hardwall_info *rect);
-static void hardwall_remove_proc(struct hardwall_info *rect);
-
-/*
- * Guard changes to the hardwall data structures.
- * This could be finer grained (e.g. one lock for the list of hardwall
- * rectangles, then separate embedded locks for each one's list of tasks),
- * but there are subtle correctness issues when trying to start with
- * a task's "hardwall" pointer and lock the correct rectangle's embedded
- * lock in the presence of a simultaneous deactivation, so it seems
- * easier to have a single lock, given that none of these data
- * structures are touched very frequently during normal operation.
- */
-static DEFINE_SPINLOCK(hardwall_lock);
+static void hardwall_add_proc(struct hardwall_info *);
+static void hardwall_remove_proc(struct hardwall_info *);
 
 /* Allow disabling UDN access. */
-static int udn_disabled;
 static int __init noudn(char *str)
 {
 pr_info("User-space UDN access is disabled\n");
-udn_disabled = 1;
+hardwall_types[HARDWALL_UDN].disabled = 1;
 return 0;
 }
 early_param("noudn", noudn);
 
+#ifndef __tilepro__
+/* Allow disabling IDN access. */
+static int __init noidn(char *str)
+{
+pr_info("User-space IDN access is disabled\n");
+hardwall_types[HARDWALL_IDN].disabled = 1;
+return 0;
+}
+early_param("noidn", noidn);
+
+/* Allow disabling IPI access. */
+static int __init noipi(char *str)
+{
+pr_info("User-space IPI access is disabled\n");
+hardwall_types[HARDWALL_IPI].disabled = 1;
+return 0;
+}
+early_param("noipi", noipi);
+#endif
+
 
 /*
- * Low-level primitives
+ * Low-level primitives for UDN/IDN
  */
 
+#ifdef __tilepro__
+#define mtspr_XDN(hwt, name, val) \
+do { (void)(hwt); __insn_mtspr(SPR_UDN_##name, (val)); } while (0)
+#define mtspr_MPL_XDN(hwt, name, val) \
+do { (void)(hwt); __insn_mtspr(SPR_MPL_UDN_##name, (val)); } while (0)
+#define mfspr_XDN(hwt, name) \
+((void)(hwt), __insn_mfspr(SPR_UDN_##name))
+#else
+#define mtspr_XDN(hwt, name, val)\
+do {\
+if ((hwt)-&amp;gt;is_idn)\
+__insn_mtspr(SPR_IDN_##name, (val));\
+else\
+__insn_mtspr(SPR_UDN_##name, (val));\
+} while (0)
+#define mtspr_MPL_XDN(hwt, name, val)\
+do {\
+if ((hwt)-&amp;gt;is_idn)\
+__insn_mtspr(SPR_MPL_IDN_##name, (val));\
+else\
+__insn_mtspr(SPR_MPL_UDN_##name, (val));\
+} while (0)
+#define mfspr_XDN(hwt, name) \
+  ((hwt)-&amp;gt;is_idn ? __insn_mfspr(SPR_IDN_##name) : __insn_mfspr(SPR_UDN_##name))
+#endif
+
 /* Set a CPU bit if the CPU is online. */
 #define cpu_online_set(cpu, dst) do { \
 if (cpu_online(cpu))          \
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,7 +199,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int contains(struct hardwall_info *r, int x, int y)
 }
 
 /* Compute the rectangle parameters and validate the cpumask. */
-static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
+static int check_rectangle(struct hardwall_info *r, struct cpumask *mask)
 {
 int x, y, cpu, ulhc, lrhc;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -114,8 +212,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
 r-&amp;gt;ulhc_y = cpu_y(ulhc);
 r-&amp;gt;width = cpu_x(lrhc) - r-&amp;gt;ulhc_x + 1;
 r-&amp;gt;height = cpu_y(lrhc) - r-&amp;gt;ulhc_y + 1;
-cpumask_copy(&amp;amp;r-&amp;gt;cpumask, mask);
-r-&amp;gt;id = ulhc;   /* The ulhc cpu id can be the hardwall id. */
 
 /* Width and height must be positive */
 if (r-&amp;gt;width &amp;lt;= 0 || r-&amp;gt;height &amp;lt;= 0)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -128,7 +224,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
 return -EINVAL;
 
 /*
- * Note that offline cpus can't be drained when this UDN
+ * Note that offline cpus can't be drained when this user network
  * rectangle eventually closes.  We used to detect this
  * situation and print a warning, but it annoyed users and
  * they ignored it anyway, so now we just return without a
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -137,16 +233,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int setup_rectangle(struct hardwall_info *r, struct cpumask *mask)
 return 0;
 }
 
-/* Do the two given rectangles overlap on any cpu? */
-static int overlaps(struct hardwall_info *a, struct hardwall_info *b)
-{
-return a-&amp;gt;ulhc_x + a-&amp;gt;width &amp;gt; b-&amp;gt;ulhc_x &amp;amp;&amp;amp;    /* A not to the left */
-b-&amp;gt;ulhc_x + b-&amp;gt;width &amp;gt; a-&amp;gt;ulhc_x &amp;amp;&amp;amp;   /* B not to the left */
-a-&amp;gt;ulhc_y + a-&amp;gt;height &amp;gt; b-&amp;gt;ulhc_y &amp;amp;&amp;amp;  /* A not above */
-b-&amp;gt;ulhc_y + b-&amp;gt;height &amp;gt; a-&amp;gt;ulhc_y;    /* B not above */
-}
-
-
 /*
  * Hardware management of hardwall setup, teardown, trapping,
  * and enabling/disabling PL0 access to the networks.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -157,23 +243,35 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; enum direction_protect {
 N_PROTECT = (1 &amp;lt;&amp;lt; 0),
 E_PROTECT = (1 &amp;lt;&amp;lt; 1),
 S_PROTECT = (1 &amp;lt;&amp;lt; 2),
-W_PROTECT = (1 &amp;lt;&amp;lt; 3)
+W_PROTECT = (1 &amp;lt;&amp;lt; 3),
+C_PROTECT = (1 &amp;lt;&amp;lt; 4),
 };
 
-static void enable_firewall_interrupts(void)
+static inline int xdn_which_interrupt(struct hardwall_type *hwt)
+{
+#ifndef __tilepro__
+if (hwt-&amp;gt;is_idn)
+return INT_IDN_FIREWALL;
+#endif
+return INT_UDN_FIREWALL;
+}
+
+static void enable_firewall_interrupts(struct hardwall_type *hwt)
 {
-arch_local_irq_unmask_now(INT_UDN_FIREWALL);
+arch_local_irq_unmask_now(xdn_which_interrupt(hwt));
 }
 
-static void disable_firewall_interrupts(void)
+static void disable_firewall_interrupts(struct hardwall_type *hwt)
 {
-arch_local_irq_mask_now(INT_UDN_FIREWALL);
+arch_local_irq_mask_now(xdn_which_interrupt(hwt));
 }
 
 /* Set up hardwall on this cpu based on the passed hardwall_info. */
-static void hardwall_setup_ipi_func(void *info)
+static void hardwall_setup_func(void *info)
 {
 struct hardwall_info *r = info;
+struct hardwall_type *hwt = r-&amp;gt;type;
+
 int cpu = smp_processor_id();
 int x = cpu % smp_width;
 int y = cpu / smp_width;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -187,13 +285,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void hardwall_setup_ipi_func(void *info)
 if (y == r-&amp;gt;ulhc_y + r-&amp;gt;height - 1)
 bits |= S_PROTECT;
 BUG_ON(bits == 0);
-__insn_mtspr(SPR_UDN_DIRECTION_PROTECT, bits);
-enable_firewall_interrupts();
-
+mtspr_XDN(hwt, DIRECTION_PROTECT, bits);
+enable_firewall_interrupts(hwt);
 }
 
 /* Set up all cpus on edge of rectangle to enable/disable hardwall SPRs. */
-static void hardwall_setup(struct hardwall_info *r)
+static void hardwall_protect_rectangle(struct hardwall_info *r)
 {
 int x, y, cpu, delta;
 struct cpumask rect_cpus;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -217,37 +314,50 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void hardwall_setup(struct hardwall_info *r)
 }
 
 /* Then tell all the cpus to set up their protection SPR */
-on_each_cpu_mask(&amp;amp;rect_cpus, hardwall_setup_ipi_func, r, 1);
+on_each_cpu_mask(&amp;amp;rect_cpus, hardwall_setup_func, r, 1);
 }
 
 void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
 {
 struct hardwall_info *rect;
+struct hardwall_type *hwt;
 struct task_struct *p;
 struct siginfo info;
-int x, y;
 int cpu = smp_processor_id();
 int found_processes;
 unsigned long flags;
-
 struct pt_regs *old_regs = set_irq_regs(regs);
+
 irq_enter();
 
+/* Figure out which network trapped. */
+switch (fault_num) {
+#ifndef __tilepro__
+case INT_IDN_FIREWALL:
+hwt = &amp;amp;hardwall_types[HARDWALL_IDN];
+break;
+#endif
+case INT_UDN_FIREWALL:
+hwt = &amp;amp;hardwall_types[HARDWALL_UDN];
+break;
+default:
+BUG();
+}
+BUG_ON(hwt-&amp;gt;disabled);
+
 /* This tile trapped a network access; find the rectangle. */
-x = cpu % smp_width;
-y = cpu / smp_width;
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-list_for_each_entry(rect, &amp;amp;rectangles, list) {
-if (contains(rect, x, y))
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+list_for_each_entry(rect, &amp;amp;hwt-&amp;gt;list, list) {
+if (cpumask_test_cpu(cpu, &amp;amp;rect-&amp;gt;cpumask))
 break;
 }
 
 /*
  * It shouldn't be possible not to find this cpu on the
  * rectangle list, since only cpus in rectangles get hardwalled.
- * The hardwall is only removed after the UDN is drained.
+ * The hardwall is only removed after the user network is drained.
  */
-BUG_ON(&amp;amp;rect-&amp;gt;list == &amp;amp;rectangles);
+BUG_ON(&amp;amp;rect-&amp;gt;list == &amp;amp;hwt-&amp;gt;list);
 
 /*
  * If we already started teardown on this hardwall, don't worry;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -255,30 +365,32 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
  * to quiesce.
  */
 if (rect-&amp;gt;teardown_in_progress) {
-pr_notice("cpu %d: detected hardwall violation %#lx"
+pr_notice("cpu %d: detected %s hardwall violation %#lx"
        " while teardown already in progress\n",
-       cpu, (long) __insn_mfspr(SPR_UDN_DIRECTION_PROTECT));
+  cpu, hwt-&amp;gt;name,
+  (long)mfspr_XDN(hwt, DIRECTION_PROTECT));
 goto done;
 }
 
 /*
  * Kill off any process that is activated in this rectangle.
  * We bypass security to deliver the signal, since it must be
- * one of the activated processes that generated the UDN
+ * one of the activated processes that generated the user network
  * message that caused this trap, and all the activated
  * processes shared a single open file so are pretty tightly
  * bound together from a security point of view to begin with.
  */
 rect-&amp;gt;teardown_in_progress = 1;
 wmb(); /* Ensure visibility of rectangle before notifying processes. */
-pr_notice("cpu %d: detected hardwall violation %#lx...\n",
-       cpu, (long) __insn_mfspr(SPR_UDN_DIRECTION_PROTECT));
+pr_notice("cpu %d: detected %s hardwall violation %#lx...\n",
+  cpu, hwt-&amp;gt;name, (long)mfspr_XDN(hwt, DIRECTION_PROTECT));
 info.si_signo = SIGILL;
 info.si_errno = 0;
 info.si_code = ILL_HARDWALL;
 found_processes = 0;
-list_for_each_entry(p, &amp;amp;rect-&amp;gt;task_head, thread.hardwall_list) {
-BUG_ON(p-&amp;gt;thread.hardwall != rect);
+list_for_each_entry(p, &amp;amp;rect-&amp;gt;task_head,
+    thread.hardwall[hwt-&amp;gt;index].list) {
+BUG_ON(p-&amp;gt;thread.hardwall[hwt-&amp;gt;index].info != rect);
 if (!(p-&amp;gt;flags &amp;amp; PF_EXITING)) {
 found_processes = 1;
 pr_notice("hardwall: killing %d\n", p-&amp;gt;pid);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -289,7 +401,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
 pr_notice("hardwall: no associated processes!\n");
 
  done:
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
 
 /*
  * We have to disable firewall interrupts now, or else when we
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -298,48 +410,87 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __kprobes do_hardwall_trap(struct pt_regs* regs, int fault_num)
  * haven't yet drained the network, and that would allow packets
  * to cross out of the hardwall region.
  */
-disable_firewall_interrupts();
+disable_firewall_interrupts(hwt);
 
 irq_exit();
 set_irq_regs(old_regs);
 }
 
-/* Allow access from user space to the UDN. */
-void grant_network_mpls(void)
+/* Allow access from user space to the user network. */
+void grant_hardwall_mpls(struct hardwall_type *hwt)
 {
-__insn_mtspr(SPR_MPL_UDN_ACCESS_SET_0, 1);
-__insn_mtspr(SPR_MPL_UDN_AVAIL_SET_0, 1);
-__insn_mtspr(SPR_MPL_UDN_COMPLETE_SET_0, 1);
-__insn_mtspr(SPR_MPL_UDN_TIMER_SET_0, 1);
+#ifndef __tilepro__
+if (!hwt-&amp;gt;is_xdn) {
+__insn_mtspr(SPR_MPL_IPI_0_SET_0, 1);
+return;
+}
+#endif
+mtspr_MPL_XDN(hwt, ACCESS_SET_0, 1);
+mtspr_MPL_XDN(hwt, AVAIL_SET_0, 1);
+mtspr_MPL_XDN(hwt, COMPLETE_SET_0, 1);
+mtspr_MPL_XDN(hwt, TIMER_SET_0, 1);
 #if !CHIP_HAS_REV1_XDN()
-__insn_mtspr(SPR_MPL_UDN_REFILL_SET_0, 1);
-__insn_mtspr(SPR_MPL_UDN_CA_SET_0, 1);
+mtspr_MPL_XDN(hwt, REFILL_SET_0, 1);
+mtspr_MPL_XDN(hwt, CA_SET_0, 1);
 #endif
 }
 
-/* Deny access from user space to the UDN. */
-void restrict_network_mpls(void)
+/* Deny access from user space to the user network. */
+void restrict_hardwall_mpls(struct hardwall_type *hwt)
 {
-__insn_mtspr(SPR_MPL_UDN_ACCESS_SET_1, 1);
-__insn_mtspr(SPR_MPL_UDN_AVAIL_SET_1, 1);
-__insn_mtspr(SPR_MPL_UDN_COMPLETE_SET_1, 1);
-__insn_mtspr(SPR_MPL_UDN_TIMER_SET_1, 1);
+#ifndef __tilepro__
+if (!hwt-&amp;gt;is_xdn) {
+__insn_mtspr(SPR_MPL_IPI_0_SET_1, 1);
+return;
+}
+#endif
+mtspr_MPL_XDN(hwt, ACCESS_SET_1, 1);
+mtspr_MPL_XDN(hwt, AVAIL_SET_1, 1);
+mtspr_MPL_XDN(hwt, COMPLETE_SET_1, 1);
+mtspr_MPL_XDN(hwt, TIMER_SET_1, 1);
 #if !CHIP_HAS_REV1_XDN()
-__insn_mtspr(SPR_MPL_UDN_REFILL_SET_1, 1);
-__insn_mtspr(SPR_MPL_UDN_CA_SET_1, 1);
+mtspr_MPL_XDN(hwt, REFILL_SET_1, 1);
+mtspr_MPL_XDN(hwt, CA_SET_1, 1);
 #endif
 }
 
+/* Restrict or deny as necessary for the task we're switching to. */
+void hardwall_switch_tasks(struct task_struct *prev,
+   struct task_struct *next)
+{
+int i;
+for (i = 0; i &amp;lt; HARDWALL_TYPES; ++i) {
+if (prev-&amp;gt;thread.hardwall[i].info != NULL) {
+if (next-&amp;gt;thread.hardwall[i].info == NULL)
+restrict_hardwall_mpls(&amp;amp;hardwall_types[i]);
+} else if (next-&amp;gt;thread.hardwall[i].info != NULL) {
+grant_hardwall_mpls(&amp;amp;hardwall_types[i]);
+}
+}
+}
+
+/* Does this task have the right to IPI the given cpu? */
+int hardwall_ipi_valid(int cpu)
+{
+#ifdef __tilegx__
+struct hardwall_info *info =
+current-&amp;gt;thread.hardwall[HARDWALL_IPI].info;
+return info &amp;amp;&amp;amp; cpumask_test_cpu(cpu, &amp;amp;info-&amp;gt;cpumask);
+#else
+return 0;
+#endif
+}
 
 /*
- * Code to create, activate, deactivate, and destroy hardwall rectangles.
+ * Code to create, activate, deactivate, and destroy hardwall resources.
  */
 
-/* Create a hardwall for the given rectangle */
-static struct hardwall_info *hardwall_create(
-size_t size, const unsigned char __user *bits)
+/* Create a hardwall for the given resource */
+static struct hardwall_info *hardwall_create(struct hardwall_type *hwt,
+     size_t size,
+     const unsigned char __user *bits)
 {
-struct hardwall_info *iter, *rect;
+struct hardwall_info *iter, *info;
 struct cpumask mask;
 unsigned long flags;
 int rc;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -370,55 +521,62 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static struct hardwall_info *hardwall_create(
 }
 }
 
-/* Allocate a new rectangle optimistically. */
-rect = kmalloc(sizeof(struct hardwall_info),
+/* Allocate a new hardwall_info optimistically. */
+info = kmalloc(sizeof(struct hardwall_info),
 GFP_KERNEL | __GFP_ZERO);
-if (rect == NULL)
+if (info == NULL)
 return ERR_PTR(-ENOMEM);
-INIT_LIST_HEAD(&amp;amp;rect-&amp;gt;task_head);
+INIT_LIST_HEAD(&amp;amp;info-&amp;gt;task_head);
+info-&amp;gt;type = hwt;
 
 /* Compute the rectangle size and validate that it's plausible. */
-rc = setup_rectangle(rect, &amp;amp;mask);
-if (rc != 0) {
-kfree(rect);
-return ERR_PTR(rc);
+cpumask_copy(&amp;amp;info-&amp;gt;cpumask, &amp;amp;mask);
+info-&amp;gt;id = find_first_bit(cpumask_bits(&amp;amp;mask), nr_cpumask_bits);
+if (hwt-&amp;gt;is_xdn) {
+rc = check_rectangle(info, &amp;amp;mask);
+if (rc != 0) {
+kfree(info);
+return ERR_PTR(rc);
+}
 }
 
 /* Confirm it doesn't overlap and add it to the list. */
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-list_for_each_entry(iter, &amp;amp;rectangles, list) {
-if (overlaps(iter, rect)) {
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
-kfree(rect);
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+list_for_each_entry(iter, &amp;amp;hwt-&amp;gt;list, list) {
+if (cpumask_intersects(&amp;amp;iter-&amp;gt;cpumask, &amp;amp;info-&amp;gt;cpumask)) {
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
+kfree(info);
 return ERR_PTR(-EBUSY);
 }
 }
-list_add_tail(&amp;amp;rect-&amp;gt;list, &amp;amp;rectangles);
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
+list_add_tail(&amp;amp;info-&amp;gt;list, &amp;amp;hwt-&amp;gt;list);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
 
 /* Set up appropriate hardwalling on all affected cpus. */
-hardwall_setup(rect);
+if (hwt-&amp;gt;is_xdn)
+hardwall_protect_rectangle(info);
 
 /* Create a /proc/tile/hardwall entry. */
-hardwall_add_proc(rect);
+hardwall_add_proc(info);
 
-return rect;
+return info;
 }
 
 /* Activate a given hardwall on this cpu for this process. */
-static int hardwall_activate(struct hardwall_info *rect)
+static int hardwall_activate(struct hardwall_info *info)
 {
-int cpu, x, y;
+int cpu;
 unsigned long flags;
 struct task_struct *p = current;
 struct thread_struct *ts = &amp;amp;p-&amp;gt;thread;
+struct hardwall_type *hwt;
 
-/* Require a rectangle. */
-if (rect == NULL)
+/* Require a hardwall. */
+if (info == NULL)
 return -ENODATA;
 
-/* Not allowed to activate a rectangle that is being torn down. */
-if (rect-&amp;gt;teardown_in_progress)
+/* Not allowed to activate a hardwall that is being torn down. */
+if (info-&amp;gt;teardown_in_progress)
 return -EINVAL;
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -428,78 +586,87 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int hardwall_activate(struct hardwall_info *rect)
 if (cpumask_weight(&amp;amp;p-&amp;gt;cpus_allowed) != 1)
 return -EPERM;
 
-/* Make sure we are bound to a cpu in this rectangle. */
+/* Make sure we are bound to a cpu assigned to this resource. */
 cpu = smp_processor_id();
 BUG_ON(cpumask_first(&amp;amp;p-&amp;gt;cpus_allowed) != cpu);
-x = cpu_x(cpu);
-y = cpu_y(cpu);
-if (!contains(rect, x, y))
+if (!cpumask_test_cpu(cpu, &amp;amp;info-&amp;gt;cpumask))
 return -EINVAL;
 
 /* If we are already bound to this hardwall, it's a no-op. */
-if (ts-&amp;gt;hardwall) {
-BUG_ON(ts-&amp;gt;hardwall != rect);
+hwt = info-&amp;gt;type;
+if (ts-&amp;gt;hardwall[hwt-&amp;gt;index].info) {
+BUG_ON(ts-&amp;gt;hardwall[hwt-&amp;gt;index].info != info);
 return 0;
 }
 
-/* Success!  This process gets to use the user networks on this cpu. */
-ts-&amp;gt;hardwall = rect;
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-list_add(&amp;amp;ts-&amp;gt;hardwall_list, &amp;amp;rect-&amp;gt;task_head);
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
-grant_network_mpls();
-printk(KERN_DEBUG "Pid %d (%s) activated for hardwall: cpu %d\n",
-       p-&amp;gt;pid, p-&amp;gt;comm, cpu);
+/* Success!  This process gets to use the resource on this cpu. */
+ts-&amp;gt;hardwall[hwt-&amp;gt;index].info = info;
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+list_add(&amp;amp;ts-&amp;gt;hardwall[hwt-&amp;gt;index].list, &amp;amp;info-&amp;gt;task_head);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
+grant_hardwall_mpls(hwt);
+printk(KERN_DEBUG "Pid %d (%s) activated for %s hardwall: cpu %d\n",
+       p-&amp;gt;pid, p-&amp;gt;comm, hwt-&amp;gt;name, cpu);
 return 0;
 }
 
 /*
- * Deactivate a task's hardwall.  Must hold hardwall_lock.
+ * Deactivate a task's hardwall.  Must hold lock for hardwall_type.
  * This method may be called from free_task(), so we don't want to
  * rely on too many fields of struct task_struct still being valid.
  * We assume the cpus_allowed, pid, and comm fields are still valid.
  */
-static void _hardwall_deactivate(struct task_struct *task)
+static void _hardwall_deactivate(struct hardwall_type *hwt,
+ struct task_struct *task)
 {
 struct thread_struct *ts = &amp;amp;task-&amp;gt;thread;
 
 if (cpumask_weight(&amp;amp;task-&amp;gt;cpus_allowed) != 1) {
-pr_err("pid %d (%s) releasing networks with"
+pr_err("pid %d (%s) releasing %s hardwall with"
        " an affinity mask containing %d cpus!\n",
-       task-&amp;gt;pid, task-&amp;gt;comm,
+       task-&amp;gt;pid, task-&amp;gt;comm, hwt-&amp;gt;name,
        cpumask_weight(&amp;amp;task-&amp;gt;cpus_allowed));
 BUG();
 }
 
-BUG_ON(ts-&amp;gt;hardwall == NULL);
-ts-&amp;gt;hardwall = NULL;
-list_del(&amp;amp;ts-&amp;gt;hardwall_list);
+BUG_ON(ts-&amp;gt;hardwall[hwt-&amp;gt;index].info == NULL);
+ts-&amp;gt;hardwall[hwt-&amp;gt;index].info = NULL;
+list_del(&amp;amp;ts-&amp;gt;hardwall[hwt-&amp;gt;index].list);
 if (task == current)
-restrict_network_mpls();
+restrict_hardwall_mpls(hwt);
 }
 
 /* Deactivate a task's hardwall. */
-int hardwall_deactivate(struct task_struct *task)
+static int hardwall_deactivate(struct hardwall_type *hwt,
+       struct task_struct *task)
 {
 unsigned long flags;
 int activated;
 
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-activated = (task-&amp;gt;thread.hardwall != NULL);
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+activated = (task-&amp;gt;thread.hardwall[hwt-&amp;gt;index].info != NULL);
 if (activated)
-_hardwall_deactivate(task);
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
+_hardwall_deactivate(hwt, task);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
 
 if (!activated)
 return -EINVAL;
 
-printk(KERN_DEBUG "Pid %d (%s) deactivated for hardwall: cpu %d\n",
-       task-&amp;gt;pid, task-&amp;gt;comm, smp_processor_id());
+printk(KERN_DEBUG "Pid %d (%s) deactivated for %s hardwall: cpu %d\n",
+       task-&amp;gt;pid, task-&amp;gt;comm, hwt-&amp;gt;name, smp_processor_id());
 return 0;
 }
 
-/* Stop a UDN switch before draining the network. */
-static void stop_udn_switch(void *ignored)
+void hardwall_deactivate_all(struct task_struct *task)
+{
+int i;
+for (i = 0; i &amp;lt; HARDWALL_TYPES; ++i)
+if (task-&amp;gt;thread.hardwall[i].info)
+hardwall_deactivate(&amp;amp;hardwall_types[i], task);
+}
+
+/* Stop the switch before draining the network. */
+static void stop_xdn_switch(void *arg)
 {
 #if !CHIP_HAS_REV1_XDN()
 /* Freeze the switch and the demux. */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -507,13 +674,71 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void stop_udn_switch(void *ignored)
      SPR_UDN_SP_FREEZE__SP_FRZ_MASK |
      SPR_UDN_SP_FREEZE__DEMUX_FRZ_MASK |
      SPR_UDN_SP_FREEZE__NON_DEST_EXT_MASK);
+#else
+/*
+ * Drop all packets bound for the core or off the edge.
+ * We rely on the normal hardwall protection setup code
+ * to have set the low four bits to trigger firewall interrupts,
+ * and shift those bits up to trigger "drop on send" semantics,
+ * plus adding "drop on send to core" for all switches.
+ * In practice it seems the switches latch the DIRECTION_PROTECT
+ * SPR so they won't start dropping if they're already
+ * delivering the last message to the core, but it doesn't
+ * hurt to enable it here.
+ */
+struct hardwall_type *hwt = arg;
+unsigned long protect = mfspr_XDN(hwt, DIRECTION_PROTECT);
+mtspr_XDN(hwt, DIRECTION_PROTECT, (protect | C_PROTECT) &amp;lt;&amp;lt; 5);
 #endif
 }
 
+static void empty_xdn_demuxes(struct hardwall_type *hwt)
+{
+#ifndef __tilepro__
+if (hwt-&amp;gt;is_idn) {
+while (__insn_mfspr(SPR_IDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 0))
+(void) __tile_idn0_receive();
+while (__insn_mfspr(SPR_IDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 1))
+(void) __tile_idn1_receive();
+return;
+}
+#endif
+while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 0))
+(void) __tile_udn0_receive();
+while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 1))
+(void) __tile_udn1_receive();
+while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 2))
+(void) __tile_udn2_receive();
+while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 3))
+(void) __tile_udn3_receive();
+}
+
 /* Drain all the state from a stopped switch. */
-static void drain_udn_switch(void *ignored)
+static void drain_xdn_switch(void *arg)
 {
-#if !CHIP_HAS_REV1_XDN()
+struct hardwall_info *info = arg;
+struct hardwall_type *hwt = info-&amp;gt;type;
+
+#if CHIP_HAS_REV1_XDN()
+/*
+ * The switches have been configured to drop any messages
+ * destined for cores (or off the edge of the rectangle).
+ * But the current message may continue to be delivered,
+ * so we wait until all the cores have finished any pending
+ * messages before we stop draining.
+ */
+int pending = mfspr_XDN(hwt, PENDING);
+while (pending--) {
+empty_xdn_demuxes(hwt);
+if (hwt-&amp;gt;is_idn)
+__tile_idn_send(0);
+else
+__tile_udn_send(0);
+}
+atomic_dec(&amp;amp;info-&amp;gt;xdn_pending_count);
+while (atomic_read(&amp;amp;info-&amp;gt;xdn_pending_count))
+empty_xdn_demuxes(hwt);
+#else
 int i;
 int from_tile_words, ca_count;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -533,15 +758,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void drain_udn_switch(void *ignored)
 (void) __insn_mfspr(SPR_UDN_DEMUX_WRITE_FIFO);
 
 /* Empty out demuxes. */
-while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 0))
-(void) __tile_udn0_receive();
-while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 1))
-(void) __tile_udn1_receive();
-while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 2))
-(void) __tile_udn2_receive();
-while (__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; (1 &amp;lt;&amp;lt; 3))
-(void) __tile_udn3_receive();
-BUG_ON((__insn_mfspr(SPR_UDN_DATA_AVAIL) &amp;amp; 0xF) != 0);
+empty_xdn_demuxes(hwt);
 
 /* Empty out catch all. */
 ca_count = __insn_mfspr(SPR_UDN_DEMUX_CA_COUNT);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -563,21 +780,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void drain_udn_switch(void *ignored)
 #endif
 }
 
-/* Reset random UDN state registers at boot up and during hardwall teardown. */
-void reset_network_state(void)
+/* Reset random XDN state registers at boot up and during hardwall teardown. */
+static void reset_xdn_network_state(struct hardwall_type *hwt)
 {
-#if !CHIP_HAS_REV1_XDN()
-/* Reset UDN coordinates to their standard value */
-unsigned int cpu = smp_processor_id();
-unsigned int x = cpu % smp_width;
-unsigned int y = cpu / smp_width;
-#endif
-
-if (udn_disabled)
+if (hwt-&amp;gt;disabled)
 return;
 
+/* Clear out other random registers so we have a clean slate. */
+mtspr_XDN(hwt, DIRECTION_PROTECT, 0);
+mtspr_XDN(hwt, AVAIL_EN, 0);
+mtspr_XDN(hwt, DEADLOCK_TIMEOUT, 0);
+
 #if !CHIP_HAS_REV1_XDN()
-__insn_mtspr(SPR_UDN_TILE_COORD, (x &amp;lt;&amp;lt; 18) | (y &amp;lt;&amp;lt; 7));
+/* Reset UDN coordinates to their standard value */
+{
+unsigned int cpu = smp_processor_id();
+unsigned int x = cpu % smp_width;
+unsigned int y = cpu / smp_width;
+__insn_mtspr(SPR_UDN_TILE_COORD, (x &amp;lt;&amp;lt; 18) | (y &amp;lt;&amp;lt; 7));
+}
 
 /* Set demux tags to predefined values and enable them. */
 __insn_mtspr(SPR_UDN_TAG_VALID, 0xf);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -585,56 +806,50 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void reset_network_state(void)
 __insn_mtspr(SPR_UDN_TAG_1, (1 &amp;lt;&amp;lt; 1));
 __insn_mtspr(SPR_UDN_TAG_2, (1 &amp;lt;&amp;lt; 2));
 __insn_mtspr(SPR_UDN_TAG_3, (1 &amp;lt;&amp;lt; 3));
-#endif
 
-/* Clear out other random registers so we have a clean slate. */
-__insn_mtspr(SPR_UDN_AVAIL_EN, 0);
-__insn_mtspr(SPR_UDN_DEADLOCK_TIMEOUT, 0);
-#if !CHIP_HAS_REV1_XDN()
+/* Set other rev0 random registers to a clean state. */
 __insn_mtspr(SPR_UDN_REFILL_EN, 0);
 __insn_mtspr(SPR_UDN_DEMUX_QUEUE_SEL, 0);
 __insn_mtspr(SPR_UDN_SP_FIFO_SEL, 0);
-#endif
 
 /* Start the switch and demux. */
-#if !CHIP_HAS_REV1_XDN()
 __insn_mtspr(SPR_UDN_SP_FREEZE, 0);
 #endif
 }
 
-/* Restart a UDN switch after draining. */
-static void restart_udn_switch(void *ignored)
+void reset_network_state(void)
 {
-reset_network_state();
-
-/* Disable firewall interrupts. */
-__insn_mtspr(SPR_UDN_DIRECTION_PROTECT, 0);
-disable_firewall_interrupts();
+reset_xdn_network_state(&amp;amp;hardwall_types[HARDWALL_UDN]);
+#ifndef __tilepro__
+reset_xdn_network_state(&amp;amp;hardwall_types[HARDWALL_IDN]);
+#endif
 }
 
-/* Build a struct cpumask containing all valid tiles in bounding rectangle. */
-static void fill_mask(struct hardwall_info *r, struct cpumask *result)
+/* Restart an XDN switch after draining. */
+static void restart_xdn_switch(void *arg)
 {
-int x, y, cpu;
+struct hardwall_type *hwt = arg;
 
-cpumask_clear(result);
+#if CHIP_HAS_REV1_XDN()
+/* One last drain step to avoid races with injection and draining. */
+empty_xdn_demuxes(hwt);
+#endif
 
-cpu = r-&amp;gt;ulhc_y * smp_width + r-&amp;gt;ulhc_x;
-for (y = 0; y &amp;lt; r-&amp;gt;height; ++y, cpu += smp_width - r-&amp;gt;width) {
-for (x = 0; x &amp;lt; r-&amp;gt;width; ++x, ++cpu)
-cpu_online_set(cpu, result);
-}
+reset_xdn_network_state(hwt);
+
+/* Disable firewall interrupts. */
+disable_firewall_interrupts(hwt);
 }
 
 /* Last reference to a hardwall is gone, so clear the network. */
-static void hardwall_destroy(struct hardwall_info *rect)
+static void hardwall_destroy(struct hardwall_info *info)
 {
 struct task_struct *task;
+struct hardwall_type *hwt;
 unsigned long flags;
-struct cpumask mask;
 
-/* Make sure this file actually represents a rectangle. */
-if (rect == NULL)
+/* Make sure this file actually represents a hardwall. */
+if (info == NULL)
 return;
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -644,39 +859,53 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void hardwall_destroy(struct hardwall_info *rect)
  * deactivate any remaining tasks before freeing the
  * hardwall_info object itself.
  */
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-list_for_each_entry(task, &amp;amp;rect-&amp;gt;task_head, thread.hardwall_list)
-_hardwall_deactivate(task);
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
-
-/* Drain the UDN. */
-printk(KERN_DEBUG "Clearing hardwall rectangle %dx%d %d,%d\n",
-       rect-&amp;gt;width, rect-&amp;gt;height, rect-&amp;gt;ulhc_x, rect-&amp;gt;ulhc_y);
-fill_mask(rect, &amp;amp;mask);
-on_each_cpu_mask(&amp;amp;mask, stop_udn_switch, NULL, 1);
-on_each_cpu_mask(&amp;amp;mask, drain_udn_switch, NULL, 1);
+hwt = info-&amp;gt;type;
+info-&amp;gt;teardown_in_progress = 1;
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+list_for_each_entry(task, &amp;amp;info-&amp;gt;task_head,
+    thread.hardwall[hwt-&amp;gt;index].list)
+_hardwall_deactivate(hwt, task);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
+
+if (hwt-&amp;gt;is_xdn) {
+/* Configure the switches for draining the user network. */
+printk(KERN_DEBUG
+       "Clearing %s hardwall rectangle %dx%d %d,%d\n",
+       hwt-&amp;gt;name, info-&amp;gt;width, info-&amp;gt;height,
+       info-&amp;gt;ulhc_x, info-&amp;gt;ulhc_y);
+on_each_cpu_mask(&amp;amp;info-&amp;gt;cpumask, stop_xdn_switch, hwt, 1);
+
+/* Drain the network. */
+#if CHIP_HAS_REV1_XDN()
+atomic_set(&amp;amp;info-&amp;gt;xdn_pending_count,
+   cpumask_weight(&amp;amp;info-&amp;gt;cpumask));
+on_each_cpu_mask(&amp;amp;info-&amp;gt;cpumask, drain_xdn_switch, info, 0);
+#else
+on_each_cpu_mask(&amp;amp;info-&amp;gt;cpumask, drain_xdn_switch, info, 1);
+#endif
 
-/* Restart switch and disable firewall. */
-on_each_cpu_mask(&amp;amp;mask, restart_udn_switch, NULL, 1);
+/* Restart switch and disable firewall. */
+on_each_cpu_mask(&amp;amp;info-&amp;gt;cpumask, restart_xdn_switch, hwt, 1);
+}
 
 /* Remove the /proc/tile/hardwall entry. */
-hardwall_remove_proc(rect);
-
-/* Now free the rectangle from the list. */
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-BUG_ON(!list_empty(&amp;amp;rect-&amp;gt;task_head));
-list_del(&amp;amp;rect-&amp;gt;list);
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
-kfree(rect);
+hardwall_remove_proc(info);
+
+/* Now free the hardwall from the list. */
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+BUG_ON(!list_empty(&amp;amp;info-&amp;gt;task_head));
+list_del(&amp;amp;info-&amp;gt;list);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
+kfree(info);
 }
 
 
 static int hardwall_proc_show(struct seq_file *sf, void *v)
 {
-struct hardwall_info *rect = sf-&amp;gt;private;
+struct hardwall_info *info = sf-&amp;gt;private;
 char buf[256];
 
-int rc = cpulist_scnprintf(buf, sizeof(buf), &amp;amp;rect-&amp;gt;cpumask);
+int rc = cpulist_scnprintf(buf, sizeof(buf), &amp;amp;info-&amp;gt;cpumask);
 buf[rc++] = '\n';
 seq_write(sf, buf, rc);
 return 0;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -695,31 +924,45 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static const struct file_operations hardwall_proc_fops = {
 .release= single_release,
 };
 
-static void hardwall_add_proc(struct hardwall_info *rect)
+static void hardwall_add_proc(struct hardwall_info *info)
 {
 char buf[64];
-snprintf(buf, sizeof(buf), "%d", rect-&amp;gt;id);
-proc_create_data(buf, 0444, hardwall_proc_dir,
- &amp;amp;hardwall_proc_fops, rect);
+snprintf(buf, sizeof(buf), "%d", info-&amp;gt;id);
+proc_create_data(buf, 0444, info-&amp;gt;type-&amp;gt;proc_dir,
+ &amp;amp;hardwall_proc_fops, info);
 }
 
-static void hardwall_remove_proc(struct hardwall_info *rect)
+static void hardwall_remove_proc(struct hardwall_info *info)
 {
 char buf[64];
-snprintf(buf, sizeof(buf), "%d", rect-&amp;gt;id);
-remove_proc_entry(buf, hardwall_proc_dir);
+snprintf(buf, sizeof(buf), "%d", info-&amp;gt;id);
+remove_proc_entry(buf, info-&amp;gt;type-&amp;gt;proc_dir);
 }
 
 int proc_pid_hardwall(struct task_struct *task, char *buffer)
 {
-struct hardwall_info *rect = task-&amp;gt;thread.hardwall;
-return rect ? sprintf(buffer, "%d\n", rect-&amp;gt;id) : 0;
+int i;
+int n = 0;
+for (i = 0; i &amp;lt; HARDWALL_TYPES; ++i) {
+struct hardwall_info *info = task-&amp;gt;thread.hardwall[i].info;
+if (info)
+n += sprintf(&amp;amp;buffer[n], "%s: %d\n",
+     info-&amp;gt;type-&amp;gt;name, info-&amp;gt;id);
+}
+return n;
 }
 
 void proc_tile_hardwall_init(struct proc_dir_entry *root)
 {
-if (!udn_disabled)
-hardwall_proc_dir = proc_mkdir("hardwall", root);
+int i;
+for (i = 0; i &amp;lt; HARDWALL_TYPES; ++i) {
+struct hardwall_type *hwt = &amp;amp;hardwall_types[i];
+if (hwt-&amp;gt;disabled)
+continue;
+if (hardwall_proc_dir == NULL)
+hardwall_proc_dir = proc_mkdir("hardwall", root);
+hwt-&amp;gt;proc_dir = proc_mkdir(hwt-&amp;gt;name, hardwall_proc_dir);
+}
 }
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -729,34 +972,45 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void proc_tile_hardwall_init(struct proc_dir_entry *root)
 
 static long hardwall_ioctl(struct file *file, unsigned int a, unsigned long b)
 {
-struct hardwall_info *rect = file-&amp;gt;private_data;
+struct hardwall_info *info = file-&amp;gt;private_data;
+int minor = iminor(file-&amp;gt;f_mapping-&amp;gt;host);
+struct hardwall_type* hwt;
 
 if (_IOC_TYPE(a) != HARDWALL_IOCTL_BASE)
 return -EINVAL;
 
+BUILD_BUG_ON(HARDWALL_TYPES != _HARDWALL_TYPES);
+BUILD_BUG_ON(HARDWALL_TYPES !=
+     sizeof(hardwall_types)/sizeof(hardwall_types[0]));
+
+if (minor &amp;lt; 0 || minor &amp;gt;= HARDWALL_TYPES)
+return -EINVAL;
+hwt = &amp;amp;hardwall_types[minor];
+WARN_ON(info &amp;amp;&amp;amp; hwt != info-&amp;gt;type);
+
 switch (_IOC_NR(a)) {
 case _HARDWALL_CREATE:
-if (udn_disabled)
+if (hwt-&amp;gt;disabled)
 return -ENOSYS;
-if (rect != NULL)
+if (info != NULL)
 return -EALREADY;
-rect = hardwall_create(_IOC_SIZE(a),
-(const unsigned char __user *)b);
-if (IS_ERR(rect))
-return PTR_ERR(rect);
-file-&amp;gt;private_data = rect;
+info = hardwall_create(hwt, _IOC_SIZE(a),
+       (const unsigned char __user *)b);
+if (IS_ERR(info))
+return PTR_ERR(info);
+file-&amp;gt;private_data = info;
 return 0;
 
 case _HARDWALL_ACTIVATE:
-return hardwall_activate(rect);
+return hardwall_activate(info);
 
 case _HARDWALL_DEACTIVATE:
-if (current-&amp;gt;thread.hardwall != rect)
+if (current-&amp;gt;thread.hardwall[hwt-&amp;gt;index].info != info)
 return -EINVAL;
-return hardwall_deactivate(current);
+return hardwall_deactivate(hwt, current);
 
 case _HARDWALL_GET_ID:
-return rect ? rect-&amp;gt;id : -EINVAL;
+return info ? info-&amp;gt;id : -EINVAL;
 
 default:
 return -EINVAL;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -775,26 +1029,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static long hardwall_compat_ioctl(struct file *file,
 /* The user process closed the file; revoke access to user networks. */
 static int hardwall_flush(struct file *file, fl_owner_t owner)
 {
-struct hardwall_info *rect = file-&amp;gt;private_data;
+struct hardwall_info *info = file-&amp;gt;private_data;
 struct task_struct *task, *tmp;
 unsigned long flags;
 
-if (rect) {
+if (info) {
 /*
  * NOTE: if multiple threads are activated on this hardwall
  * file, the other threads will continue having access to the
- * UDN until they are context-switched out and back in again.
+ * user network until they are context-switched out and back
+ * in again.
  *
  * NOTE: A NULL files pointer means the task is being torn
  * down, so in that case we also deactivate it.
  */
-spin_lock_irqsave(&amp;amp;hardwall_lock, flags);
-list_for_each_entry_safe(task, tmp, &amp;amp;rect-&amp;gt;task_head,
- thread.hardwall_list) {
+struct hardwall_type *hwt = info-&amp;gt;type;
+spin_lock_irqsave(&amp;amp;hwt-&amp;gt;lock, flags);
+list_for_each_entry_safe(task, tmp, &amp;amp;info-&amp;gt;task_head,
+ thread.hardwall[hwt-&amp;gt;index].list) {
 if (task-&amp;gt;files == owner || task-&amp;gt;files == NULL)
-_hardwall_deactivate(task);
+_hardwall_deactivate(hwt, task);
 }
-spin_unlock_irqrestore(&amp;amp;hardwall_lock, flags);
+spin_unlock_irqrestore(&amp;amp;hwt-&amp;gt;lock, flags);
 }
 
 return 0;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -824,11 +1080,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __init dev_hardwall_init(void)
 int rc;
 dev_t dev;
 
-rc = alloc_chrdev_region(&amp;amp;dev, 0, 1, "hardwall");
+rc = alloc_chrdev_region(&amp;amp;dev, 0, HARDWALL_TYPES, "hardwall");
 if (rc &amp;lt; 0)
 return rc;
 cdev_init(&amp;amp;hardwall_dev, &amp;amp;dev_hardwall_fops);
-rc = cdev_add(&amp;amp;hardwall_dev, dev, 1);
+rc = cdev_add(&amp;amp;hardwall_dev, dev, HARDWALL_TYPES);
 if (rc &amp;lt; 0)
 return rc;
 
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 0ae8723..7c06d59 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1257,7 +1257,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(fill_ra_stack)
 int_hand     INT_UNALIGN_DATA, UNALIGN_DATA, int_unalign
 int_hand     INT_DTLB_MISS, DTLB_MISS, do_page_fault
 int_hand     INT_DTLB_ACCESS, DTLB_ACCESS, do_page_fault
-int_hand     INT_IDN_FIREWALL, IDN_FIREWALL, bad_intr
+int_hand     INT_IDN_FIREWALL, IDN_FIREWALL, do_hardwall_trap
 int_hand     INT_UDN_FIREWALL, UDN_FIREWALL, do_hardwall_trap
 int_hand     INT_TILE_TIMER, TILE_TIMER, do_timer_interrupt
 int_hand     INT_IDN_TIMER, IDN_TIMER, bad_intr
diff --git a/arch/tile/kernel/process.c b/arch/tile/kernel/process.c
index 54e6c64..03448eb 100644
--- a/arch/tile/kernel/process.c
+++ b/arch/tile/kernel/process.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -145,10 +145,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void free_thread_info(struct thread_info *info)
  * Calling deactivate here just frees up the data structures.
  * If the task we're freeing held the last reference to a
  * hardwall fd, it would have been released prior to this point
- * anyway via exit_files(), and "hardwall" would be NULL by now.
+ * anyway via exit_files(), and the hardwall_task.info pointers
+ * would be NULL by now.
  */
-if (info-&amp;gt;task-&amp;gt;thread.hardwall)
-hardwall_deactivate(info-&amp;gt;task);
+hardwall_deactivate_all(info-&amp;gt;task);
 #endif
 
 if (step_state) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -264,7 +264,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int copy_thread(unsigned long clone_flags, unsigned long sp,
 
 #ifdef CONFIG_HARDWALL
 /* New thread does not own any networks. */
-p-&amp;gt;thread.hardwall = NULL;
+memset(&amp;amp;p-&amp;gt;thread.hardwall[0], 0,
+       sizeof(struct hardwall_task) * HARDWALL_TYPES);
 #endif
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -534,12 +535,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct task_struct *__sched _switch_to(struct task_struct *prev,
 
 #ifdef CONFIG_HARDWALL
 /* Enable or disable access to the network registers appropriately. */
-if (prev-&amp;gt;thread.hardwall != NULL) {
-if (next-&amp;gt;thread.hardwall == NULL)
-restrict_network_mpls();
-} else if (next-&amp;gt;thread.hardwall != NULL) {
-grant_network_mpls();
-}
+hardwall_switch_tasks(prev, next);
 #endif
 
 /*
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323186">
    <title>x86/mce Add validation check before GHES error is recorded</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323186</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=8571723a698dcc0ee16c1c63908aa99dd940ce5c
Commit:     8571723a698dcc0ee16c1c63908aa99dd940ce5c
Parent:     95022b8cf6ed7f3292b60c8e85fe59a12bfb1c9e
Author:     Chen Gong &amp;lt;gong.chen&amp;lt; at &amp;gt;linux.intel.com&amp;gt;
AuthorDate: Fri Apr 20 16:02:05 2012 -0700
Committer:  Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
CommitDate: Fri Apr 20 16:02:05 2012 -0700

    x86/mce Add validation check before GHES error is recorded
    
    When GHES error record is logged into mcelog kernel buffer, a validation
    check for physical address is necessary, which prevents reporting an
    invalid physical address.
    
    [Since physical address is the only useful element in this error record,
    we drop generating the record completely if we don't have a valid address]
    
    Signed-off-by: Chen Gong &amp;lt;gong.chen&amp;lt; at &amp;gt;linux.intel.com&amp;gt;
    Signed-off-by: Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
---
 arch/x86/kernel/cpu/mcheck/mce-apei.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce-apei.c b/arch/x86/kernel/cpu/mcheck/mce-apei.c
index 507ea58..cd8b166 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-apei.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-apei.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -42,7 +42,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void apei_mce_report_mem_error(int corrected, struct cper_sec_mem_err *mem_err)
 struct mce m;
 
 /* Only corrected MC is reported */
-if (!corrected)
+if (!corrected || !(mem_err-&amp;gt;validation_bits &amp;amp;
+CPER_MEM_VALID_PHYSICAL_ADDRESS))
 return;
 
 mce_setup(&amp;amp;m);
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323185">
    <title>tile/mm/fault.c: Port OOM changes to handle_page_fault</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323185</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=4ce6bea220f1a40aba928bd5624ada833ee1c52b
Commit:     4ce6bea220f1a40aba928bd5624ada833ee1c52b
Parent:     c6f696f69ab352b17f5c97f721e646b53b91f643
Author:     Kautuk Consul &amp;lt;consul.kautuk&amp;lt; at &amp;gt;gmail.com&amp;gt;
AuthorDate: Sat Mar 31 08:05:39 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:29 2012 -0400

    tile/mm/fault.c: Port OOM changes to handle_page_fault
    
    Commit d065bd810b6deb67d4897a14bfe21f8eb526ba99
    (mm: retry page fault when blocking on disk transfer) and
    commit 37b23e0525d393d48a7d59f870b3bc061a30ccdb
    (x86,mm: make pagefault killable)
    
    The above commits introduced changes into the x86 pagefault handler
    for making the page fault handler retryable as well as killable.
    
    These changes reduce the mmap_sem hold time, which is crucial
    during OOM killer invocation.
    
    Port these changes to tile.
    
    Signed-off-by: Kautuk Consul &amp;lt;consul.kautuk&amp;lt; at &amp;gt;gmail.com&amp;gt;
    [cmetcalf&amp;lt; at &amp;gt;tilera.com: initialize "flags" after "write" updated.]
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/mm/fault.c |   32 +++++++++++++++++++++++++++-----
 1 files changed, 27 insertions(+), 5 deletions(-)

diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 54f18fc..84ce7ab 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -273,11 +273,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int handle_page_fault(struct pt_regs *regs,
 int si_code;
 int is_kernel_mode;
 pgd_t *pgd;
+unsigned int flags;
 
 /* on TILE, protection faults are always writes */
 if (!is_page_fault)
 write = 1;
 
+flags = (FAULT_FLAG_ALLOW_RETRY | FAULT_FLAG_KILLABLE |
+ (write ? FAULT_FLAG_WRITE : 0));
+
 is_kernel_mode = (EX1_PL(regs-&amp;gt;ex1) != USER_PL);
 
 tsk = validate_current();
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -382,6 +386,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int handle_page_fault(struct pt_regs *regs,
 vma = NULL;  /* happy compiler */
 goto bad_area_nosemaphore;
 }
+
+retry:
 down_read(&amp;amp;mm-&amp;gt;mmap_sem);
 }
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -429,7 +435,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; good_area:
  * make sure we exit gracefully rather than endlessly redo
  * the fault.
  */
-fault = handle_mm_fault(mm, vma, address, write);
+fault = handle_mm_fault(mm, vma, address, flags);
+
+if ((fault &amp;amp; VM_FAULT_RETRY) &amp;amp;&amp;amp; fatal_signal_pending(current))
+return 0;
+
 if (unlikely(fault &amp;amp; VM_FAULT_ERROR)) {
 if (fault &amp;amp; VM_FAULT_OOM)
 goto out_of_memory;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -437,10 +447,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; good_area:
 goto do_sigbus;
 BUG();
 }
-if (fault &amp;amp; VM_FAULT_MAJOR)
-tsk-&amp;gt;maj_flt++;
-else
-tsk-&amp;gt;min_flt++;
+if (flags &amp;amp; FAULT_FLAG_ALLOW_RETRY) {
+if (fault &amp;amp; VM_FAULT_MAJOR)
+tsk-&amp;gt;maj_flt++;
+else
+tsk-&amp;gt;min_flt++;
+if (fault &amp;amp; VM_FAULT_RETRY) {
+flags &amp;amp;= ~FAULT_FLAG_ALLOW_RETRY;
+
+ /*
+  * No need to up_read(&amp;amp;mm-&amp;gt;mmap_sem) as we would
+  * have already released it in __lock_page_or_retry
+  * in mm/filemap.c.
+  */
+goto retry;
+}
+}
 
 #if CHIP_HAS_TILE_DMA() || CHIP_HAS_SN_PROC()
 /*
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323184">
    <title>x86/mce: Fix check for processor context when machine check was taken.</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323184</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=875e26648cf9b6db9d8dc07b7959d7c61fb3f49c
Commit:     875e26648cf9b6db9d8dc07b7959d7c61fb3f49c
Parent:     a129a7c84582629741e5fa6f40026efcd7a65bd4
Author:     Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
AuthorDate: Wed May 23 14:14:22 2012 -0700
Committer:  Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
CommitDate: Wed May 23 14:22:44 2012 -0700

    x86/mce: Fix check for processor context when machine check was taken.
    
    Linus pointed out that there was no value is checking whether m-&amp;gt;ip
    was zero - because zero is a legimate value.  If we have a reliable
    (or faked in the VM86 case) "m-&amp;gt;cs" we can use it to tell whether we
    were in user mode or kernelwhen the machine check hit.
    
    Reported-by: Linus Torvalds &amp;lt;torvalds&amp;lt; at &amp;gt;linuxfoundation.org&amp;gt;
    Cc: &amp;lt;stable&amp;lt; at &amp;gt;vger.kernel.org&amp;gt;
    Signed-off-by: Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
---
 arch/x86/kernel/cpu/mcheck/mce-severity.c |   16 ++++++++++------
 1 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
index 0c82091..1ccd453 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -165,15 +165,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static struct severity {
 };
 
 /*
- * If the EIPV bit is set, it means the saved IP is the
- * instruction which caused the MCE.
+ * If mcgstatus indicated that ip/cs on the stack were
+ * no good, then "m-&amp;gt;cs" will be zero and we will have
+ * to assume the worst case (IN_KERNEL) as we actually
+ * have no idea what we were executing when the machine
+ * check hit.
+ * If we do have a good "m-&amp;gt;cs" (or a faked one in the
+ * case we were executing in VM86 mode) we can use it to
+ * distinguish an exception taken in user from from one
+ * taken in the kernel.
  */
 static int error_context(struct mce *m)
 {
-if (m-&amp;gt;mcgstatus &amp;amp; MCG_STATUS_EIPV)
-return (m-&amp;gt;ip &amp;amp;&amp;amp; (m-&amp;gt;cs &amp;amp; 3) == 3) ? IN_USER : IN_KERNEL;
-/* Unknown, assume kernel */
-return IN_KERNEL;
+return ((m-&amp;gt;cs &amp;amp; 3) == 3) ? IN_USER : IN_KERNEL;
 }
 
 int mce_severity(struct mce *m, int tolerant, char **msg)
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323183">
    <title>arch/tile: use interrupt critical sections less</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323183</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=51007004f44c9588d70ffb77e1f52479bd5b0e37
Commit:     51007004f44c9588d70ffb77e1f52479bd5b0e37
Parent:     76e10d158efb6d4516018846f60c2ab5501900bc
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Tue Mar 27 15:40:20 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:20 2012 -0400

    arch/tile: use interrupt critical sections less
    
    In general we want to avoid ever touching memory while within an
    interrupt critical section, since the page fault path goes through
    a different path from the hypervisor when in an interrupt critical
    section, and we carefully decided with tilegx that we didn't need
    to support this path in the kernel.  (On tilepro we did implement
    that path as part of supporting atomic instructions in software.)
    
    In practice we always need to touch the kernel stack, since that's
    where we store the interrupt state before releasing the critical
    section, but this change cleans up a few things.  The IRQ_ENABLE
    macro is split up so that when we want to enable interrupts in a
    deferred way (e.g. for cpu_idle or for interrupt return) we can
    read the per-cpu enable mask before entering the critical section.
    The cache-migration code is changed to use interrupt masking instead
    of interrupt critical sections.  And, the interrupt-entry code is
    changed so that we defer loading "tp" from per-cpu data until after
    we have released the interrupt critical section.
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/asm/irqflags.h |   34 +++++++++++++----
 arch/tile/kernel/entry.S         |    3 +-
 arch/tile/kernel/intvec_64.S     |   78 +++++++++++++++++++++-----------------
 arch/tile/mm/init.c              |    4 ++
 arch/tile/mm/migrate.h           |    6 +++
 arch/tile/mm/migrate_32.S        |   36 ++++-------------
 arch/tile/mm/migrate_64.S        |   34 +++-------------
 7 files changed, 96 insertions(+), 99 deletions(-)

diff --git a/arch/tile/include/asm/irqflags.h b/arch/tile/include/asm/irqflags.h
index 5db0ce5..b4e96fe 100644
--- a/arch/tile/include/asm/irqflags.h
+++ b/arch/tile/include/asm/irqflags.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -28,10 +28,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  */
 #if CHIP_HAS_AUX_PERF_COUNTERS()
 #define LINUX_MASKABLE_INTERRUPTS_HI \
-       (~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT)))
+(~(INT_MASK_HI(INT_PERF_COUNT) | INT_MASK_HI(INT_AUX_PERF_COUNT)))
 #else
 #define LINUX_MASKABLE_INTERRUPTS_HI \
-       (~(INT_MASK_HI(INT_PERF_COUNT)))
+(~(INT_MASK_HI(INT_PERF_COUNT)))
 #endif
 
 #else
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -90,6 +90,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_0, (unsigned long)(__m)); \
 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K_1, (unsigned long)(__m&amp;gt;&amp;gt;32)); \
 } while (0)
+#define interrupt_mask_save_mask() \
+(__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_0) | \
+ (((unsigned long long)__insn_mfspr(SPR_INTERRUPT_MASK_SET_K_1))&amp;lt;&amp;lt;32))
+#define interrupt_mask_restore_mask(mask) do { \
+unsigned long long __m = (mask); \
+__insn_mtspr(SPR_INTERRUPT_MASK_K_0, (unsigned long)(__m)); \
+__insn_mtspr(SPR_INTERRUPT_MASK_K_1, (unsigned long)(__m&amp;gt;&amp;gt;32)); \
+} while (0)
 #else
 #define interrupt_mask_set(n) \
 __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (1UL &amp;lt;&amp;lt; (n)))
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -101,6 +109,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 __insn_mtspr(SPR_INTERRUPT_MASK_SET_K, (mask))
 #define interrupt_mask_reset_mask(mask) \
 __insn_mtspr(SPR_INTERRUPT_MASK_RESET_K, (mask))
+#define interrupt_mask_save_mask() \
+__insn_mfspr(SPR_INTERRUPT_MASK_K)
+#define interrupt_mask_restore_mask(mask) \
+__insn_mtspr(SPR_INTERRUPT_MASK_K, (mask))
 #endif
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -122,7 +134,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 
 /* Disable all interrupts, including NMIs. */
 #define arch_local_irq_disable_all() \
-interrupt_mask_set_mask(-1UL)
+interrupt_mask_set_mask(-1ULL)
 
 /* Re-enable all maskable interrupts. */
 #define arch_local_irq_enable() \
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -179,7 +191,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 #ifdef __tilegx__
 
 #if INT_MEM_ERROR != 0
-# error Fix IRQ_DISABLED() macro
+# error Fix IRQS_DISABLED() macro
 #endif
 
 /* Return 0 or 1 to indicate whether interrupts are currently disabled. */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -207,9 +219,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 mtspr   SPR_INTERRUPT_MASK_SET_K, tmp
 
 /* Enable interrupts. */
-#define IRQ_ENABLE(tmp0, tmp1)\
+#define IRQ_ENABLE_LOAD(tmp0, tmp1)\
 GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0);\
-ld      tmp0, tmp0;\
+ld      tmp0, tmp0
+#define IRQ_ENABLE_APPLY(tmp0, tmp1)\
 mtspr   SPR_INTERRUPT_MASK_RESET_K, tmp0
 
 #else /* !__tilegx__ */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -253,17 +266,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; DECLARE_PER_CPU(unsigned long long, interrupts_enabled_mask);
 mtspr   SPR_INTERRUPT_MASK_SET_K_1, tmp
 
 /* Enable interrupts. */
-#define IRQ_ENABLE(tmp0, tmp1)\
+#define IRQ_ENABLE_LOAD(tmp0, tmp1)\
 GET_INTERRUPTS_ENABLED_MASK_PTR(tmp0);\
 {\
  lw     tmp0, tmp0;\
  addi   tmp1, tmp0, 4\
 };\
-lw      tmp1, tmp1;\
+lw      tmp1, tmp1
+#define IRQ_ENABLE_APPLY(tmp0, tmp1)\
 mtspr   SPR_INTERRUPT_MASK_RESET_K_0, tmp0;\
 mtspr   SPR_INTERRUPT_MASK_RESET_K_1, tmp1
 #endif
 
+#define IRQ_ENABLE(tmp0, tmp1)\
+IRQ_ENABLE_LOAD(tmp0, tmp1);\
+IRQ_ENABLE_APPLY(tmp0, tmp1)
+
 /*
  * Do the CPU's IRQ-state tracing from assembly code. We call a
  * C function, but almost everywhere we do, we don't mind clobbering
diff --git a/arch/tile/kernel/entry.S b/arch/tile/kernel/entry.S
index ec91568..133c4b5 100644
--- a/arch/tile/kernel/entry.S
+++ b/arch/tile/kernel/entry.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -100,8 +100,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(smp_nap)
  */
 STD_ENTRY(_cpu_idle)
 movei r1, 1
+IRQ_ENABLE_LOAD(r2, r3)
 mtspr INTERRUPT_CRITICAL_SECTION, r1
-IRQ_ENABLE(r2, r3)             /* unmask, but still with ICS set */
+IRQ_ENABLE_APPLY(r2, r3)       /* unmask, but still with ICS set */
 mtspr INTERRUPT_CRITICAL_SECTION, zero
 .global _cpu_idle_nap
 _cpu_idle_nap:
diff --git a/arch/tile/kernel/intvec_64.S b/arch/tile/kernel/intvec_64.S
index 30ae76e..0ae8723 100644
--- a/arch/tile/kernel/intvec_64.S
+++ b/arch/tile/kernel/intvec_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -220,7 +220,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; intvec_\vecname:
  * This routine saves just the first four registers, plus the
  * stack context so we can do proper backtracing right away,
  * and defers to handle_interrupt to save the rest.
- * The backtracer needs pc, ex1, lr, sp, r52, and faultnum.
+ * The backtracer needs pc, ex1, lr, sp, r52, and faultnum,
+ * and needs sp set to its final location at the bottom of
+ * the stack frame.
  */
 addli   r0, r0, PTREGS_OFFSET_LR - (PTREGS_SIZE + KSTK_PTREGS_GAP)
 wh64    r0   /* cache line 7 */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -450,23 +452,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; intvec_\vecname:
 push_reg r5, r52
 st      r52, r4
 
-/* Load tp with our per-cpu offset. */
-#ifdef CONFIG_SMP
-{
- mfspr  r20, SPR_SYSTEM_SAVE_K_0
- moveli r21, hw2_last(__per_cpu_offset)
-}
-{
- shl16insli r21, r21, hw1(__per_cpu_offset)
- bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
-}
-shl16insli r21, r21, hw0(__per_cpu_offset)
-shl3add r20, r20, r21
-ld      tp, r20
-#else
-move    tp, zero
-#endif
-
 /*
  * If we will be returning to the kernel, we will need to
  * reset the interrupt masks to the state they had before.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -489,6 +474,44 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; intvec_\vecname:
 .endif
 st      r21, r32
 
+/*
+ * we've captured enough state to the stack (including in
+ * particular our EX_CONTEXT state) that we can now release
+ * the interrupt critical section and replace it with our
+ * standard "interrupts disabled" mask value.  This allows
+ * synchronous interrupts (and profile interrupts) to punch
+ * through from this point onwards.
+ *
+ * It's important that no code before this point touch memory
+ * other than our own stack (to keep the invariant that this
+ * is all that gets touched under ICS), and that no code after
+ * this point reference any interrupt-specific SPR, in particular
+ * the EX_CONTEXT_K_ values.
+ */
+.ifc \function,handle_nmi
+IRQ_DISABLE_ALL(r20)
+.else
+IRQ_DISABLE(r20, r21)
+.endif
+mtspr   INTERRUPT_CRITICAL_SECTION, zero
+
+/* Load tp with our per-cpu offset. */
+#ifdef CONFIG_SMP
+{
+ mfspr  r20, SPR_SYSTEM_SAVE_K_0
+ moveli r21, hw2_last(__per_cpu_offset)
+}
+{
+ shl16insli r21, r21, hw1(__per_cpu_offset)
+ bfextu r20, r20, 0, LOG2_THREAD_SIZE-1
+}
+shl16insli r21, r21, hw0(__per_cpu_offset)
+shl3add r20, r20, r21
+ld      tp, r20
+#else
+move    tp, zero
+#endif
+
 #ifdef __COLLECT_LINKER_FEEDBACK__
 /*
  * Notify the feedback routines that we were in the
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -513,21 +536,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; intvec_\vecname:
 #endif
 
 /*
- * we've captured enough state to the stack (including in
- * particular our EX_CONTEXT state) that we can now release
- * the interrupt critical section and replace it with our
- * standard "interrupts disabled" mask value.  This allows
- * synchronous interrupts (and profile interrupts) to punch
- * through from this point onwards.
- */
-.ifc \function,handle_nmi
-IRQ_DISABLE_ALL(r20)
-.else
-IRQ_DISABLE(r20, r21)
-.endif
-mtspr   INTERRUPT_CRITICAL_SECTION, zero
-
-/*
  * Prepare the first 256 stack bytes to be rapidly accessible
  * without having to fetch the background data.
  */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -736,9 +744,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(interrupt_return)
 beqzt   r30, .Lrestore_regs
 j       3f
 2:TRACE_IRQS_ON
+IRQ_ENABLE_LOAD(r20, r21)
 movei   r0, 1
 mtspr   INTERRUPT_CRITICAL_SECTION, r0
-IRQ_ENABLE(r20, r21)
+IRQ_ENABLE_APPLY(r20, r21)
 beqzt   r30, .Lrestore_regs
 3:
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -755,7 +764,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(interrupt_return)
  * that will save some cycles if this turns out to be a syscall.
  */
 .Lrestore_regs:
-FEEDBACK_REENTER(interrupt_return)   /* called from elsewhere */
 
 /*
  * Rotate so we have one high bit and one low bit to test.
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index 6a9d20d..1e46335 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -444,6 +444,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static pgd_t pgtables[PTRS_PER_PGD]
  */
 static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
 {
+unsigned long long irqmask;
 unsigned long address, pfn;
 pmd_t *pmd;
 pte_t *pte;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -633,10 +634,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init kernel_physical_mapping_init(pgd_t *pgd_base)
  *  - install pgtables[] as the real page table
  *  - flush the TLB so the new page table takes effect
  */
+irqmask = interrupt_mask_save_mask();
+interrupt_mask_set_mask(-1ULL);
 rc = flush_and_install_context(__pa(pgtables),
        init_pgprot((unsigned long)pgtables),
        __get_cpu_var(current_asid),
        cpumask_bits(my_cpu_mask));
+interrupt_mask_restore_mask(irqmask);
 BUG_ON(rc != 0);
 
 /* Copy the page table back to the normal swapper_pg_dir. */
diff --git a/arch/tile/mm/migrate.h b/arch/tile/mm/migrate.h
index cd45a08..91683d9 100644
--- a/arch/tile/mm/migrate.h
+++ b/arch/tile/mm/migrate.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -24,6 +24,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /*
  * This function is used as a helper when setting up the initial
  * page table (swapper_pg_dir).
+ *
+ * You must mask ALL interrupts prior to invoking this code, since
+ * you can't legally touch the stack during the cache flush.
  */
 extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access,
      HV_ASID asid,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -39,6 +42,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern int flush_and_install_context(HV_PhysAddr page_table, HV_PTE access,
  *
  * Note that any non-NULL pointers must not point to the page that
  * is handled by the stack_pte itself.
+ *
+ * You must mask ALL interrupts prior to invoking this code, since
+ * you can't legally touch the stack during the cache flush.
  */
 extern int homecache_migrate_stack_and_flush(pte_t stack_pte, unsigned long va,
      size_t length, pte_t *stack_ptep,
diff --git a/arch/tile/mm/migrate_32.S b/arch/tile/mm/migrate_32.S
index ac01a7c..5305814 100644
--- a/arch/tile/mm/migrate_32.S
+++ b/arch/tile/mm/migrate_32.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -40,8 +40,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define FRAME_R3216
 #define FRAME_R3320
 #define FRAME_R3424
-#define FRAME_R3528
-#define FRAME_SIZE32
+#define FRAME_SIZE28
 
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,12 +65,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define r_my_cpumaskr5
 
 /* Locals (callee-save); must not be more than FRAME_xxx above. */
-#define r_save_icsr30
-#define r_context_lor31
-#define r_context_hir32
-#define r_access_lor33
-#define r_access_hir34
-#define r_asidr35
+#define r_context_lor30
+#define r_context_hir31
+#define r_access_lor32
+#define r_access_hir33
+#define r_asidr34
 
 STD_ENTRY(flush_and_install_context)
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,11 +102,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
  sw r_tmp, r33
  addi r_tmp, sp, FRAME_R34
 }
-{
- sw r_tmp, r34
- addi r_tmp, sp, FRAME_R35
-}
-sw r_tmp, r35
+sw r_tmp, r34
 
 /* Move some arguments to callee-save registers. */
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -121,13 +115,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 move r_asid, r_asid_in
 
-/* Disable interrupts, since we can't use our stack. */
-{
- mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
- movei r_tmp, 1
-}
-mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
-
 /* First, flush our L2 cache. */
 {
  move r0, zero  /* cache_pa */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -163,7 +150,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 {
  move r4, r_asid
- movei r5, HV_CTX_DIRECTIO
+ moveli r5, HV_CTX_DIRECTIO | CTX_PAGE_FLAG
 }
 jal hv_install_context
 bnz r0, .Ldone
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -175,9 +162,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 
 .Ldone:
-/* Reset interrupts back how they were before. */
-mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
-
 /* Restore the callee-saved registers and return. */
 addli lr, sp, FRAME_SIZE
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -202,10 +186,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 {
  lw r34, r_tmp
- addli r_tmp, sp, FRAME_R35
-}
-{
- lw r35, r_tmp
  addi sp, sp, FRAME_SIZE
 }
 jrp lr
diff --git a/arch/tile/mm/migrate_64.S b/arch/tile/mm/migrate_64.S
index e76fea6..1d15b10 100644
--- a/arch/tile/mm/migrate_64.S
+++ b/arch/tile/mm/migrate_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,8 +38,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define FRAME_R3016
 #define FRAME_R3124
 #define FRAME_R3232
-#define FRAME_R3340
-#define FRAME_SIZE48
+#define FRAME_SIZE40
 
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,10 +59,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define r_my_cpumaskr3
 
 /* Locals (callee-save); must not be more than FRAME_xxx above. */
-#define r_save_icsr30
-#define r_contextr31
-#define r_accessr32
-#define r_asidr33
+#define r_contextr30
+#define r_accessr31
+#define r_asidr32
 
 /*
  * Caller-save locals and frame constants are the same as
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -93,11 +91,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
  st r_tmp, r31
  addi r_tmp, sp, FRAME_R32
 }
-{
- st r_tmp, r32
- addi r_tmp, sp, FRAME_R33
-}
-st r_tmp, r33
+st r_tmp, r32
 
 /* Move some arguments to callee-save registers. */
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -106,13 +100,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 move r_asid, r_asid_in
 
-/* Disable interrupts, since we can't use our stack. */
-{
- mfspr r_save_ics, INTERRUPT_CRITICAL_SECTION
- movei r_tmp, 1
-}
-mtspr INTERRUPT_CRITICAL_SECTION, r_tmp
-
 /* First, flush our L2 cache. */
 {
  move r0, zero  /* cache_pa */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -147,7 +134,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
 }
 {
  move r2, r_asid
- movei r3, HV_CTX_DIRECTIO
+ moveli r3, HV_CTX_DIRECTIO | CTX_PAGE_FLAG
 }
 jal hv_install_context
 bnez r0, 1f
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -158,10 +145,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(flush_and_install_context)
  jal hv_flush_all
 }
 
-1:      /* Reset interrupts back how they were before. */
-mtspr INTERRUPT_CRITICAL_SECTION, r_save_ics
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323182">
    <title>arch/tile: support multiple huge page sizes dynamically</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323182</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=621b19551507c8fd9d721f4038509c5bb155a983
Commit:     621b19551507c8fd9d721f4038509c5bb155a983
Parent:     d9ed9faac283a3be73f0e11a2ef49ee55aece4db
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Sun Apr 1 14:04:21 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:27 2012 -0400

    arch/tile: support multiple huge page sizes dynamically
    
    This change adds support for a new "super" bit in the PTE, using the new
    arch_make_huge_pte() method.  The Tilera hypervisor sees the bit set at a
    given level of the page table and gangs together 4, 16, or 64 consecutive
    pages from that level of the hierarchy to create a larger TLB entry.
    
    One extra "super" page size can be specified at each of the three levels
    of the page table hierarchy on tilegx, using the "hugepagesz" argument
    on the boot command line.  A new hypervisor API is added to allow Linux
    to tell the hypervisor how many PTEs to gang together at each level of
    the page table.
    
    To allow pre-allocating huge pages larger than the buddy allocator can
    handle, this change modifies the Tilera bootmem support to put all of
    memory on tilegx platforms into bootmem.
    
    As part of this change I eliminate the vestigial CONFIG_HIGHPTE support,
    which never worked anyway, and eliminate the hv_page_size() API in favor
    of the standard vma_kernel_pagesize() API.
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/Kconfig                 |    8 +
 arch/tile/include/asm/hugetlb.h   |   21 +++
 arch/tile/include/asm/page.h      |    5 +-
 arch/tile/include/asm/pgtable.h   |   12 +-
 arch/tile/include/asm/tlbflush.h  |   17 +--
 arch/tile/include/hv/hypervisor.h |   70 +++++++++-
 arch/tile/kernel/hvglue.lds       |    3 +-
 arch/tile/kernel/proc.c           |    1 +
 arch/tile/kernel/setup.c          |  161 ++++++++++++++-------
 arch/tile/kernel/tlb.c            |   11 +-
 arch/tile/mm/fault.c              |    2 +-
 arch/tile/mm/homecache.c          |    1 +
 arch/tile/mm/hugetlbpage.c        |  285 ++++++++++++++++++++++++++++---------
 arch/tile/mm/init.c               |    4 +
 arch/tile/mm/pgtable.c            |   13 --
 15 files changed, 456 insertions(+), 158 deletions(-)

diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index 38c3957..cc56642 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -47,6 +47,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config NEED_PER_CPU_PAGE_FIRST_CHUNK
 config SYS_SUPPORTS_HUGETLBFS
 def_bool y
 
+# Support for additional huge page sizes besides HPAGE_SIZE.
+# The software support is currently only present in the TILE-Gx
+# hypervisor. TILEPro in any case does not support page sizes
+# larger than the default HPAGE_SIZE.
+config HUGETLB_SUPER_PAGES
+depends on HUGETLB_PAGE &amp;amp;&amp;amp; TILEGX
+def_bool y
+
 config GENERIC_CLOCKEVENTS
 def_bool y
 
diff --git a/arch/tile/include/asm/hugetlb.h b/arch/tile/include/asm/hugetlb.h
index d396d18..b204238 100644
--- a/arch/tile/include/asm/hugetlb.h
+++ b/arch/tile/include/asm/hugetlb.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -106,4 +106,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void arch_release_hugepage(struct page *page)
 {
 }
 
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+       struct page *page, int writable)
+{
+size_t pagesize = huge_page_size(hstate_vma(vma));
+if (pagesize != PUD_SIZE &amp;amp;&amp;amp; pagesize != PMD_SIZE)
+entry = pte_mksuper(entry);
+return entry;
+}
+#define arch_make_huge_pte arch_make_huge_pte
+
+/* Sizes to scale up page size for PTEs with HV_PTE_SUPER bit. */
+enum {
+HUGE_SHIFT_PGDIR = 0,
+HUGE_SHIFT_PMD = 1,
+HUGE_SHIFT_PAGE = 2,
+HUGE_SHIFT_ENTRIES
+};
+extern int huge_shift[HUGE_SHIFT_ENTRIES];
+#endif
+
 #endif /* _ASM_TILE_HUGETLB_H */
diff --git a/arch/tile/include/asm/page.h b/arch/tile/include/asm/page.h
index c750943..9d9131e 100644
--- a/arch/tile/include/asm/page.h
+++ b/arch/tile/include/asm/page.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -87,8 +87,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; typedef HV_PTE pgprot_t;
 /*
  * User L2 page tables are managed as one L2 page table per page,
  * because we use the page allocator for them.  This keeps the allocation
- * simple and makes it potentially useful to implement HIGHPTE at some point.
- * However, it's also inefficient, since L2 page tables are much smaller
+ * simple, but it's also inefficient, since L2 page tables are much smaller
  * than pages (currently 2KB vs 64KB).  So we should revisit this.
  */
 typedef struct page *pgtable_t;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -137,7 +136,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline __attribute_const__ int get_order(unsigned long size)
 
 #define HUGETLB_PAGE_ORDER(HPAGE_SHIFT - PAGE_SHIFT)
 
-#define HUGE_MAX_HSTATE2
+#define HUGE_MAX_HSTATE6
 
 #ifdef CONFIG_HUGETLB_PAGE
 #define HAVE_ARCH_HUGETLB_UNMAPPED_AREA
diff --git a/arch/tile/include/asm/pgtable.h b/arch/tile/include/asm/pgtable.h
index 319f482..73b1a4c 100644
--- a/arch/tile/include/asm/pgtable.h
+++ b/arch/tile/include/asm/pgtable.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -71,6 +71,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern void set_page_homes(void);
 
 #define _PAGE_PRESENT           HV_PTE_PRESENT
 #define _PAGE_HUGE_PAGE         HV_PTE_PAGE
+#define _PAGE_SUPER_PAGE        HV_PTE_SUPER
 #define _PAGE_READABLE          HV_PTE_READABLE
 #define _PAGE_WRITABLE          HV_PTE_WRITABLE
 #define _PAGE_EXECUTABLE        HV_PTE_EXECUTABLE
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -87,6 +88,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern void set_page_homes(void);
 #define _PAGE_ALL (\
   _PAGE_PRESENT | \
   _PAGE_HUGE_PAGE | \
+  _PAGE_SUPER_PAGE | \
   _PAGE_READABLE | \
   _PAGE_WRITABLE | \
   _PAGE_EXECUTABLE | \
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -197,6 +199,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void __pte_clear(pte_t *ptep)
 #define pte_write hv_pte_get_writable
 #define pte_exec hv_pte_get_executable
 #define pte_huge hv_pte_get_page
+#define pte_super hv_pte_get_super
 #define pte_rdprotect hv_pte_clear_readable
 #define pte_exprotect hv_pte_clear_executable
 #define pte_mkclean hv_pte_clear_dirty
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -209,6 +212,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void __pte_clear(pte_t *ptep)
 #define pte_mkyoung hv_pte_set_accessed
 #define pte_mkwrite hv_pte_set_writable
 #define pte_mkhuge hv_pte_set_page
+#define pte_mksuper hv_pte_set_super
 
 #define pte_special(pte) 0
 #define pte_mkspecial(pte) (pte)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -338,13 +342,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
  */
 #define pgd_offset_k(address) pgd_offset(&amp;amp;init_mm, address)
 
-#if defined(CONFIG_HIGHPTE)
-extern pte_t *pte_offset_map(pmd_t *, unsigned long address);
-#define pte_unmap(pte) kunmap_atomic(pte)
-#else
 #define pte_offset_map(dir, address) pte_offset_kernel(dir, address)
 #define pte_unmap(pte) do { } while (0)
-#endif
 
 /* Clear a non-executable kernel PTE and flush it from the TLB. */
 #define kpte_clear_flush(ptep, vaddr)\
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -537,7 +536,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline pte_t *pte_offset_kernel(pmd_t *pmd, unsigned long address)
 /* Support /proc/NN/pgtable API. */
 struct seq_file;
 int arch_proc_pgtable_show(struct seq_file *m, struct mm_struct *mm,
-   unsigned long vaddr, pte_t *ptep, void **datap);
+   unsigned long vaddr, unsigned long pagesize,
+   pte_t *ptep, void **datap);
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/tile/include/asm/tlbflush.h b/arch/tile/include/asm/tlbflush.h
index 96199d2..dcf91b2 100644
--- a/arch/tile/include/asm/tlbflush.h
+++ b/arch/tile/include/asm/tlbflush.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -38,16 +38,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; DECLARE_PER_CPU(int, current_asid);
 /* The hypervisor tells us what ASIDs are available to us. */
 extern int min_asid, max_asid;
 
-static inline unsigned long hv_page_size(const struct vm_area_struct *vma)
-{
-return (vma-&amp;gt;vm_flags &amp;amp; VM_HUGETLB) ? HPAGE_SIZE : PAGE_SIZE;
-}
-
 /* Pass as vma pointer for non-executable mapping, if no vma available. */
-#define FLUSH_NONEXEC ((const struct vm_area_struct *)-1UL)
+#define FLUSH_NONEXEC ((struct vm_area_struct *)-1UL)
 
 /* Flush a single user page on this cpu. */
-static inline void local_flush_tlb_page(const struct vm_area_struct *vma,
+static inline void local_flush_tlb_page(struct vm_area_struct *vma,
 unsigned long addr,
 unsigned long page_size)
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -60,7 +55,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void local_flush_tlb_page(const struct vm_area_struct *vma,
 }
 
 /* Flush range of user pages on this cpu. */
-static inline void local_flush_tlb_pages(const struct vm_area_struct *vma,
+static inline void local_flush_tlb_pages(struct vm_area_struct *vma,
  unsigned long addr,
  unsigned long page_size,
  unsigned long len)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -117,10 +112,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern void flush_tlb_all(void);
 extern void flush_tlb_kernel_range(unsigned long start, unsigned long end);
 extern void flush_tlb_current_task(void);
 extern void flush_tlb_mm(struct mm_struct *);
-extern void flush_tlb_page(const struct vm_area_struct *, unsigned long);
-extern void flush_tlb_page_mm(const struct vm_area_struct *,
+extern void flush_tlb_page(struct vm_area_struct *, unsigned long);
+extern void flush_tlb_page_mm(struct vm_area_struct *,
       struct mm_struct *, unsigned long);
-extern void flush_tlb_range(const struct vm_area_struct *,
+extern void flush_tlb_range(struct vm_area_struct *,
     unsigned long start, unsigned long end);
 
 #define flush_tlb()     flush_tlb_current_task()
diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index f278717..85e5cab 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -66,6 +66,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define HV_DEFAULT_PAGE_SIZE_LARGE \
   (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_DEFAULT_PAGE_SIZE_LARGE)
 
+#if CHIP_VA_WIDTH() &amp;gt; 32
+
+/** The log2 of the initial size of jumbo pages, in bytes.
+ * See HV_DEFAULT_PAGE_SIZE_JUMBO.
+ */
+#define HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO 32
+
+/** The initial size of jumbo pages, in bytes. This value should
+ * be verified at runtime by calling hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO).
+ * It may also be modified when installing a new context.
+ */
+#define HV_DEFAULT_PAGE_SIZE_JUMBO \
+  (__HV_SIZE_ONE &amp;lt;&amp;lt; HV_LOG2_DEFAULT_PAGE_SIZE_JUMBO)
+
+#endif
+
 /** The log2 of the granularity at which page tables must be aligned;
  *  in other words, the CPA for a page table must have this many zero
  *  bits at the bottom of the address.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -284,8 +300,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #define HV_DISPATCH_GET_IPI_PTE                   56
 #endif
 
+/** hv_set_pte_super_shift */
+#define HV_DISPATCH_SET_PTE_SUPER_SHIFT           57
+
 /** One more than the largest dispatch value */
-#define _HV_DISPATCH_END                          57
+#define _HV_DISPATCH_END                          58
 
 
 #ifndef __ASSEMBLER__
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -413,6 +432,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; typedef enum {
    */
   HV_SYSCONF_VALID_PAGE_SIZES = 7,
 
+  /** The size of jumbo pages, in bytes.
+   * If no jumbo pages are available, zero will be returned.
+   */
+  HV_SYSCONF_PAGE_SIZE_JUMBO = 8,
+
 } HV_SysconfQuery;
 
 /** Offset to subtract from returned Kelvin temperature to get degrees
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -695,6 +719,29 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_install_context(HV_PhysAddr page_table, HV_PTE access, HV_ASID asid,
 
 #ifndef __ASSEMBLER__
 
+
+/** Set the number of pages ganged together by HV_PTE_SUPER at a
+ * particular level of the page table.
+ *
+ * The current TILE-Gx hardware only supports powers of four
+ * (i.e. log2_count must be a multiple of two), and the requested
+ * "super" page size must be less than the span of the next level in
+ * the page table.  The largest size that can be requested is 64GB.
+ *
+ * The shift value is initially "0" for all page table levels,
+ * indicating that the HV_PTE_SUPER bit is effectively ignored.
+ *
+ * If you change the count from one non-zero value to another, the
+ * hypervisor will flush the entire TLB and TSB to avoid confusion.
+ *
+ * &amp;lt; at &amp;gt;param level Page table level (0, 1, or 2)
+ * &amp;lt; at &amp;gt;param log2_count Base-2 log of the number of pages to gang together,
+ * i.e. how much to shift left the base page size for the super page size.
+ * &amp;lt; at &amp;gt;return Zero on success, or a hypervisor error code on failure.
+ */
+int hv_set_pte_super_shift(int level, int log2_count);
+
+
 /** Value returned from hv_inquire_context(). */
 typedef struct
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1891,8 +1938,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
 #define HV_PTE_INDEX_USER            10  /**&amp;lt; Page is user-accessible */
 #define HV_PTE_INDEX_ACCESSED        11  /**&amp;lt; Page has been accessed */
 #define HV_PTE_INDEX_DIRTY           12  /**&amp;lt; Page has been written */
-                                         /*   Bits 13-15 are reserved for
+                                         /*   Bits 13-14 are reserved for
                                               future use. */
+#define HV_PTE_INDEX_SUPER           15  /**&amp;lt; Pages ganged together for TLB */
 #define HV_PTE_INDEX_MODE            16  /**&amp;lt; Page mode; see HV_PTE_MODE_xxx */
 #define HV_PTE_MODE_BITS              3  /**&amp;lt; Number of bits in mode */
 #define HV_PTE_INDEX_CLIENT2         19  /**&amp;lt; Page client state 2 */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1987,7 +2035,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
 
 /** Does this PTE map a page?
  *
- * If this bit is set in the level-1 page table, the entry should be
+ * If this bit is set in a level-0 page table, the entry should be
+ * interpreted as a level-2 page table entry mapping a jumbo page.
+ *
+ * If this bit is set in a level-1 page table, the entry should be
  * interpreted as a level-2 page table entry mapping a large page.
  *
  * This bit should not be modified by the client while PRESENT is set, as
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1997,6 +2048,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int hv_flush_remote(HV_PhysAddr cache_pa, unsigned long cache_control,
  */
 #define HV_PTE_PAGE                  (__HV_PTE_ONE &amp;lt;&amp;lt; HV_PTE_INDEX_PAGE)
 
+/** Does this PTE implicitly reference multiple pages?
+ *
+ * If this bit is set in the page table (either in the level-2 page table,
+ * or in a higher level page table in conjunction with the PAGE bit)
+ * then the PTE specifies a range of contiguous pages, not a single page.
+ * The hv_set_pte_super_shift() allows you to specify the count for
+ * each level of the page table.
+ *
+ * Note: this bit is not supported on TILEPro systems.
+ */
+#define HV_PTE_SUPER                 (__HV_PTE_ONE &amp;lt;&amp;lt; HV_PTE_INDEX_SUPER)
+
 /** Is this a global (non-ASID) mapping?
  *
  * If this bit is set, the translations established by this PTE will
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2215,6 +2278,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_pte_clear_##name(HV_PTE pte)                                 \
  */
 _HV_BIT(present,         PRESENT)
 _HV_BIT(page,            PAGE)
+_HV_BIT(super,           SUPER)
 _HV_BIT(client0,         CLIENT0)
 _HV_BIT(client1,         CLIENT1)
 _HV_BIT(client2,         CLIENT2)
diff --git a/arch/tile/kernel/hvglue.lds b/arch/tile/kernel/hvglue.lds
index 2b7cd0a..d44c5a6 100644
--- a/arch/tile/kernel/hvglue.lds
+++ b/arch/tile/kernel/hvglue.lds
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -55,4 +55,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; hv_store_mapping = TEXT_OFFSET + 0x106a0;
 hv_inquire_realpa = TEXT_OFFSET + 0x106c0;
 hv_flush_all = TEXT_OFFSET + 0x106e0;
 hv_get_ipi_pte = TEXT_OFFSET + 0x10700;
-hv_glue_internals = TEXT_OFFSET + 0x10720;
+hv_set_pte_super_shift = TEXT_OFFSET + 0x10720;
+hv_glue_internals = TEXT_OFFSET + 0x10740;
diff --git a/arch/tile/kernel/proc.c b/arch/tile/kernel/proc.c
index 446a7f5..dafc447 100644
--- a/arch/tile/kernel/proc.c
+++ b/arch/tile/kernel/proc.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -22,6 +22,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/proc_fs.h&amp;gt;
 #include &amp;lt;linux/sysctl.h&amp;gt;
 #include &amp;lt;linux/hardirq.h&amp;gt;
+#include &amp;lt;linux/hugetlb.h&amp;gt;
 #include &amp;lt;linux/mman.h&amp;gt;
 #include &amp;lt;asm/unaligned.h&amp;gt;
 #include &amp;lt;asm/pgtable.h&amp;gt;
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index 32948e2..445c220 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -28,6 +28,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/highmem.h&amp;gt;
 #include &amp;lt;linux/smp.h&amp;gt;
 #include &amp;lt;linux/timex.h&amp;gt;
+#include &amp;lt;linux/hugetlb.h&amp;gt;
 #include &amp;lt;asm/setup.h&amp;gt;
 #include &amp;lt;asm/sections.h&amp;gt;
 #include &amp;lt;asm/cacheflush.h&amp;gt;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -49,9 +50,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; char chip_model[64] __write_once;
 struct pglist_data node_data[MAX_NUMNODES] __read_mostly;
 EXPORT_SYMBOL(node_data);
 
-/* We only create bootmem data on node 0. */
-static bootmem_data_t __initdata node0_bdata;
-
 /* Information on the NUMA nodes that we compute early */
 unsigned long __cpuinitdata node_start_pfn[MAX_NUMNODES];
 unsigned long __cpuinitdata node_end_pfn[MAX_NUMNODES];
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -518,37 +516,96 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init setup_memory(void)
 #endif
 }
 
-static void __init setup_bootmem_allocator(void)
+/*
+ * On 32-bit machines, we only put bootmem on the low controller,
+ * since PAs &amp;gt; 4GB can't be used in bootmem.  In principle one could
+ * imagine, e.g., multiple 1 GB controllers all of which could support
+ * bootmem, but in practice using controllers this small isn't a
+ * particularly interesting scenario, so we just keep it simple and
+ * use only the first controller for bootmem on 32-bit machines.
+ */
+static inline int node_has_bootmem(int nid)
 {
-unsigned long bootmap_size, first_alloc_pfn, last_alloc_pfn;
+#ifdef CONFIG_64BIT
+return 1;
+#else
+return nid == 0;
+#endif
+}
 
-/* Provide a node 0 bdata. */
-NODE_DATA(0)-&amp;gt;bdata = &amp;amp;node0_bdata;
+static inline unsigned long alloc_bootmem_pfn(int nid,
+      unsigned long size,
+      unsigned long goal)
+{
+void *kva = __alloc_bootmem_node(NODE_DATA(nid), size,
+ PAGE_SIZE, goal);
+unsigned long pfn = kaddr_to_pfn(kva);
+BUG_ON(goal &amp;amp;&amp;amp; PFN_PHYS(pfn) != goal);
+return pfn;
+}
 
-#ifdef CONFIG_PCI
-/* Don't let boot memory alias the PCI region. */
-last_alloc_pfn = min(max_low_pfn, pci_reserve_start_pfn);
+static void __init setup_bootmem_allocator_node(int i)
+{
+unsigned long start, end, mapsize, mapstart;
+
+if (node_has_bootmem(i)) {
+NODE_DATA(i)-&amp;gt;bdata = &amp;amp;bootmem_node_data[i];
+} else {
+/* Share controller zero's bdata for now. */
+NODE_DATA(i)-&amp;gt;bdata = &amp;amp;bootmem_node_data[0];
+return;
+}
+
+/* Skip up to after the bss in node 0. */
+start = (i == 0) ? min_low_pfn : node_start_pfn[i];
+
+/* Only lowmem, if we're a HIGHMEM build. */
+#ifdef CONFIG_HIGHMEM
+end = node_lowmem_end_pfn[i];
 #else
-last_alloc_pfn = max_low_pfn;
+end = node_end_pfn[i];
 #endif
 
-/*
- * Initialize the boot-time allocator (with low memory only):
- * The first argument says where to put the bitmap, and the
- * second says where the end of allocatable memory is.
- */
-bootmap_size = init_bootmem(min_low_pfn, last_alloc_pfn);
+/* No memory here. */
+if (end == start)
+return;
+
+/* Figure out where the bootmem bitmap is located. */
+mapsize = bootmem_bootmap_pages(end - start);
+if (i == 0) {
+/* Use some space right before the heap on node 0. */
+mapstart = start;
+start += mapsize;
+} else {
+/* Allocate bitmap on node 0 to avoid page table issues. */
+mapstart = alloc_bootmem_pfn(0, PFN_PHYS(mapsize), 0);
+}
 
+/* Initialize a node. */
+init_bootmem_node(NODE_DATA(i), mapstart, start, end);
+
+/* Free all the space back into the allocator. */
+free_bootmem(PFN_PHYS(start), PFN_PHYS(end - start));
+
+#if defined(CONFIG_PCI)
 /*
- * Let the bootmem allocator use all the space we've given it
- * except for its own bitmap.
+ * Throw away any memory aliased by the PCI region.  FIXME: this
+ * is a temporary hack to work around bug 10502, and needs to be
+ * fixed properly.
  */
-first_alloc_pfn = min_low_pfn + PFN_UP(bootmap_size);
-if (first_alloc_pfn &amp;gt;= last_alloc_pfn)
-early_panic("Not enough memory on controller 0 for bootmem\n");
+if (pci_reserve_start_pfn &amp;lt; end &amp;amp;&amp;amp; pci_reserve_end_pfn &amp;gt; start)
+reserve_bootmem(PFN_PHYS(pci_reserve_start_pfn),
+PFN_PHYS(pci_reserve_end_pfn -
+ pci_reserve_start_pfn),
+BOOTMEM_EXCLUSIVE);
+#endif
+}
 
-free_bootmem(PFN_PHYS(first_alloc_pfn),
-     PFN_PHYS(last_alloc_pfn - first_alloc_pfn));
+static void __init setup_bootmem_allocator(void)
+{
+int i;
+for (i = 0; i &amp;lt; MAX_NUMNODES; ++i)
+setup_bootmem_allocator_node(i);
 
 #ifdef CONFIG_KEXEC
 if (crashk_res.start != crashk_res.end)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -579,14 +636,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static int __init percpu_size(void)
 return size;
 }
 
-static inline unsigned long alloc_bootmem_pfn(int size, unsigned long goal)
-{
-void *kva = __alloc_bootmem(size, PAGE_SIZE, goal);
-unsigned long pfn = kaddr_to_pfn(kva);
-BUG_ON(goal &amp;amp;&amp;amp; PFN_PHYS(pfn) != goal);
-return pfn;
-}
-
 static void __init zone_sizes_init(void)
 {
 unsigned long zones_size[MAX_NR_ZONES] = { 0 };
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -624,21 +673,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init zone_sizes_init(void)
  * though, there'll be no lowmem, so we just alloc_bootmem
  * the memmap.  There will be no percpu memory either.
  */
-if (__pfn_to_highbits(start) == 0) {
-/* In low PAs, allocate via bootmem. */
+if (i != 0 &amp;amp;&amp;amp; cpu_isset(i, isolnodes)) {
+node_memmap_pfn[i] =
+alloc_bootmem_pfn(0, memmap_size, 0);
+BUG_ON(node_percpu[i] != 0);
+} else if (node_has_bootmem(start)) {
 unsigned long goal = 0;
 node_memmap_pfn[i] =
-alloc_bootmem_pfn(memmap_size, goal);
+alloc_bootmem_pfn(i, memmap_size, 0);
 if (kdata_huge)
 goal = PFN_PHYS(lowmem_end) - node_percpu[i];
 if (node_percpu[i])
 node_percpu_pfn[i] =
-    alloc_bootmem_pfn(node_percpu[i], goal);
-} else if (cpu_isset(i, isolnodes)) {
-node_memmap_pfn[i] = alloc_bootmem_pfn(memmap_size, 0);
-BUG_ON(node_percpu[i] != 0);
+alloc_bootmem_pfn(i, node_percpu[i],
+  goal);
 } else {
-/* In high PAs, just reserve some pages. */
+/* In non-bootmem zones, just reserve some pages. */
 node_memmap_pfn[i] = node_free_pfn[i];
 node_free_pfn[i] += PFN_UP(memmap_size);
 if (!kdata_huge) {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -662,16 +712,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init zone_sizes_init(void)
 zones_size[ZONE_NORMAL] = end - start;
 #endif
 
-/*
- * Everyone shares node 0's bootmem allocator, but
- * we use alloc_remap(), above, to put the actual
- * struct page array on the individual controllers,
- * which is most of the data that we actually care about.
- * We can't place bootmem allocators on the other
- * controllers since the bootmem allocator can only
- * operate on 32-bit physical addresses.
- */
-NODE_DATA(i)-&amp;gt;bdata = NODE_DATA(0)-&amp;gt;bdata;
+/* Take zone metadata from controller 0 if we're isolnode. */
+if (node_isset(i, isolnodes))
+NODE_DATA(i)-&amp;gt;bdata = &amp;amp;bootmem_node_data[0];
 
 free_area_init_node(i, zones_size, start, NULL);
 printk(KERN_DEBUG "  Normal zone: %ld per-cpu pages\n",
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -854,6 +897,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; subsys_initcall(topology_init);
 
 #endif /* CONFIG_NUMA */
 
+/*
+ * Initialize hugepage support on this cpu.  We do this on all cores
+ * early in boot: before argument parsing for the boot cpu, and after
+ * argument parsing but before the init functions run on the secondaries.
+ * So the values we set up here in the hypervisor may be overridden on
+ * the boot cpu as arguments are parsed.
+ */
+static __cpuinit void init_super_pages(void)
+{
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+int i;
+for (i = 0; i &amp;lt; HUGE_SHIFT_ENTRIES; ++i)
+hv_set_pte_super_shift(i, huge_shift[i]);
+#endif
+}
+
 /**
  * setup_cpu() - Do all necessary per-cpu, tile-specific initialization.
  * &amp;lt; at &amp;gt;boot: Is this the boot cpu?
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -908,6 +967,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __cpuinit setup_cpu(int boot)
 /* Reset the network state on this cpu. */
 reset_network_state();
 #endif
+
+init_super_pages();
 }
 
 #ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/tile/kernel/tlb.c b/arch/tile/kernel/tlb.c
index a5f241c..3fd54d5 100644
--- a/arch/tile/kernel/tlb.c
+++ b/arch/tile/kernel/tlb.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -15,6 +15,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #include &amp;lt;linux/cpumask.h&amp;gt;
 #include &amp;lt;linux/module.h&amp;gt;
+#include &amp;lt;linux/hugetlb.h&amp;gt;
 #include &amp;lt;asm/tlbflush.h&amp;gt;
 #include &amp;lt;asm/homecache.h&amp;gt;
 #include &amp;lt;hv/hypervisor.h&amp;gt;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -49,25 +50,25 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void flush_tlb_current_task(void)
 flush_tlb_mm(current-&amp;gt;mm);
 }
 
-void flush_tlb_page_mm(const struct vm_area_struct *vma, struct mm_struct *mm,
+void flush_tlb_page_mm(struct vm_area_struct *vma, struct mm_struct *mm,
        unsigned long va)
 {
-unsigned long size = hv_page_size(vma);
+unsigned long size = vma_kernel_pagesize(vma);
 int cache = (vma-&amp;gt;vm_flags &amp;amp; VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
 flush_remote(0, cache, mm_cpumask(mm),
      va, size, size, mm_cpumask(mm), NULL, 0);
 }
 
-void flush_tlb_page(const struct vm_area_struct *vma, unsigned long va)
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long va)
 {
 flush_tlb_page_mm(vma, vma-&amp;gt;vm_mm, va);
 }
 EXPORT_SYMBOL(flush_tlb_page);
 
-void flush_tlb_range(const struct vm_area_struct *vma,
+void flush_tlb_range(struct vm_area_struct *vma,
      unsigned long start, unsigned long end)
 {
-unsigned long size = hv_page_size(vma);
+unsigned long size = vma_kernel_pagesize(vma);
 struct mm_struct *mm = vma-&amp;gt;vm_mm;
 int cache = (vma-&amp;gt;vm_flags &amp;amp; VM_EXEC) ? HV_FLUSH_EVICT_L1I : 0;
 flush_remote(0, cache, mm_cpumask(mm), start, end - start, size,
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c
index 22e58f5..54f18fc 100644
--- a/arch/tile/mm/fault.c
+++ b/arch/tile/mm/fault.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -187,7 +187,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static pgd_t *get_current_pgd(void)
 HV_Context ctx = hv_inquire_context();
 unsigned long pgd_pfn = ctx.page_table &amp;gt;&amp;gt; PAGE_SHIFT;
 struct page *pgd_page = pfn_to_page(pgd_pfn);
-BUG_ON(PageHighMem(pgd_page));   /* oops, HIGHPTE? */
+BUG_ON(PageHighMem(pgd_page));
 return (pgd_t *) __va(ctx.page_table);
 }
 
diff --git a/arch/tile/mm/homecache.c b/arch/tile/mm/homecache.c
index 499f737..dbcbdf7 100644
--- a/arch/tile/mm/homecache.c
+++ b/arch/tile/mm/homecache.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -30,6 +30,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/cache.h&amp;gt;
 #include &amp;lt;linux/smp.h&amp;gt;
 #include &amp;lt;linux/module.h&amp;gt;
+#include &amp;lt;linux/hugetlb.h&amp;gt;
 
 #include &amp;lt;asm/page.h&amp;gt;
 #include &amp;lt;asm/sections.h&amp;gt;
diff --git a/arch/tile/mm/hugetlbpage.c b/arch/tile/mm/hugetlbpage.c
index 42cfcba..812e2d0 100644
--- a/arch/tile/mm/hugetlbpage.c
+++ b/arch/tile/mm/hugetlbpage.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -27,85 +27,161 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/mman.h&amp;gt;
 #include &amp;lt;asm/tlb.h&amp;gt;
 #include &amp;lt;asm/tlbflush.h&amp;gt;
+#include &amp;lt;asm/setup.h&amp;gt;
+
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+
+/*
+ * Provide an additional huge page size (in addition to the regular default
+ * huge page size) if no "hugepagesz" arguments are specified.
+ * Note that it must be smaller than the default huge page size so
+ * that it's possible to allocate them on demand from the buddy allocator.
+ * You can change this to 64K (on a 16K build), 256K, 1M, or 4M,
+ * or not define it at all.
+ */
+#define ADDITIONAL_HUGE_SIZE (1024 * 1024UL)
+
+/* "Extra" page-size multipliers, one per level of the page table. */
+int huge_shift[HUGE_SHIFT_ENTRIES] = {
+#ifdef ADDITIONAL_HUGE_SIZE
+#define ADDITIONAL_HUGE_SHIFT __builtin_ctzl(ADDITIONAL_HUGE_SIZE / PAGE_SIZE)
+[HUGE_SHIFT_PAGE] = ADDITIONAL_HUGE_SHIFT
+#endif
+};
+
+/*
+ * This routine is a hybrid of pte_alloc_map() and pte_alloc_kernel().
+ * It assumes that L2 PTEs are never in HIGHMEM (we don't support that).
+ * It locks the user pagetable, and bumps up the mm-&amp;gt;nr_ptes field,
+ * but otherwise allocate the page table using the kernel versions.
+ */
+static pte_t *pte_alloc_hugetlb(struct mm_struct *mm, pmd_t *pmd,
+unsigned long address)
+{
+pte_t *new;
+
+if (pmd_none(*pmd)) {
+new = pte_alloc_one_kernel(mm, address);
+if (!new)
+return NULL;
+
+smp_wmb(); /* See comment in __pte_alloc */
+
+spin_lock(&amp;amp;mm-&amp;gt;page_table_lock);
+if (likely(pmd_none(*pmd))) {  /* Has another populated it ? */
+mm-&amp;gt;nr_ptes++;
+pmd_populate_kernel(mm, pmd, new);
+new = NULL;
+} else
+VM_BUG_ON(pmd_trans_splitting(*pmd));
+spin_unlock(&amp;amp;mm-&amp;gt;page_table_lock);
+if (new)
+pte_free_kernel(mm, new);
+}
+
+return pte_offset_kernel(pmd, address);
+}
+#endif
 
 pte_t *huge_pte_alloc(struct mm_struct *mm,
       unsigned long addr, unsigned long sz)
 {
 pgd_t *pgd;
 pud_t *pud;
-pte_t *pte = NULL;
 
-/* We do not yet support multiple huge page sizes. */
-BUG_ON(sz != PMD_SIZE);
+addr &amp;amp;= -sz;   /* Mask off any low bits in the address. */
 
 pgd = pgd_offset(mm, addr);
 pud = pud_alloc(mm, pgd, addr);
-if (pud)
-pte = (pte_t *) pmd_alloc(mm, pud, addr);
-BUG_ON(pte &amp;amp;&amp;amp; !pte_none(*pte) &amp;amp;&amp;amp; !pte_huge(*pte));
 
-return pte;
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+if (sz &amp;gt;= PGDIR_SIZE) {
+BUG_ON(sz != PGDIR_SIZE &amp;amp;&amp;amp;
+       sz != PGDIR_SIZE &amp;lt;&amp;lt; huge_shift[HUGE_SHIFT_PGDIR]);
+return (pte_t *)pud;
+} else {
+pmd_t *pmd = pmd_alloc(mm, pud, addr);
+if (sz &amp;gt;= PMD_SIZE) {
+BUG_ON(sz != PMD_SIZE &amp;amp;&amp;amp;
+       sz != (PMD_SIZE &amp;lt;&amp;lt; huge_shift[HUGE_SHIFT_PMD]));
+return (pte_t *)pmd;
+}
+else {
+if (sz != PAGE_SIZE &amp;lt;&amp;lt; huge_shift[HUGE_SHIFT_PAGE])
+panic("Unexpected page size %#lx\n", sz);
+return pte_alloc_hugetlb(mm, pmd, addr);
+}
+}
+#else
+BUG_ON(sz != PMD_SIZE);
+return (pte_t *) pmd_alloc(mm, pud, addr);
+#endif
 }
 
-pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
+static pte_t *get_pte(pte_t *base, int index, int level)
 {
-pgd_t *pgd;
-pud_t *pud;
-pmd_t *pmd = NULL;
-
-pgd = pgd_offset(mm, addr);
-if (pgd_present(*pgd)) {
-pud = pud_offset(pgd, addr);
-if (pud_present(*pud))
-pmd = pmd_offset(pud, addr);
+pte_t *ptep = base + index;
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+if (!pte_present(*ptep) &amp;amp;&amp;amp; huge_shift[level] != 0) {
+unsigned long mask = -1UL &amp;lt;&amp;lt; huge_shift[level];
+pte_t *super_ptep = base + (index &amp;amp; mask);
+pte_t pte = *super_ptep;
+if (pte_present(pte) &amp;amp;&amp;amp; pte_super(pte))
+ptep = super_ptep;
 }
-return (pte_t *) pmd;
+#endif
+return ptep;
 }
 
-#ifdef HUGETLB_TEST
-struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
-      int write)
+pte_t *huge_pte_offset(struct mm_struct *mm, unsigned long addr)
 {
-unsigned long start = address;
-int length = 1;
-int nr;
-struct page *page;
-struct vm_area_struct *vma;
-
-vma = find_vma(mm, addr);
-if (!vma || !is_vm_hugetlb_page(vma))
-return ERR_PTR(-EINVAL);
-
-pte = huge_pte_offset(mm, address);
+pgd_t *pgd;
+pud_t *pud;
+pmd_t *pmd;
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+pte_t *pte;
+#endif
 
-/* hugetlb should be locked, and hence, prefaulted */
-WARN_ON(!pte || pte_none(*pte));
+/* Get the top-level page table entry. */
+pgd = (pgd_t *)get_pte((pte_t *)mm-&amp;gt;pgd, pgd_index(addr), 0);
+if (!pgd_present(*pgd))
+return NULL;
 
-page = &amp;amp;pte_page(*pte)[vpfn % (HPAGE_SIZE/PAGE_SIZE)];
+/* We don't have four levels. */
+pud = pud_offset(pgd, addr);
+#ifndef __PAGETABLE_PUD_FOLDED
+# error support fourth page table level
+#endif
 
-WARN_ON(!PageHead(page));
+/* Check for an L0 huge PTE, if we have three levels. */
+#ifndef __PAGETABLE_PMD_FOLDED
+if (pud_huge(*pud))
+return (pte_t *)pud;
 
-return page;
-}
-
-int pmd_huge(pmd_t pmd)
-{
-return 0;
-}
+pmd = (pmd_t *)get_pte((pte_t *)pud_page_vaddr(*pud),
+       pmd_index(addr), 1);
+if (!pmd_present(*pmd))
+return NULL;
+#else
+pmd = pmd_offset(pud, addr);
+#endif
 
-int pud_huge(pud_t pud)
-{
-return 0;
-}
+/* Check for an L1 huge PTE. */
+if (pmd_huge(*pmd))
+return (pte_t *)pmd;
+
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+/* Check for an L2 huge PTE. */
+pte = get_pte((pte_t *)pmd_page_vaddr(*pmd), pte_index(addr), 2);
+if (!pte_present(*pte))
+return NULL;
+if (pte_super(*pte))
+return pte;
+#endif
 
-struct page *follow_huge_pmd(struct mm_struct *mm, unsigned long address,
-     pmd_t *pmd, int write)
-{
 return NULL;
 }
 
-#else
-
 struct page *follow_huge_addr(struct mm_struct *mm, unsigned long address,
       int write)
 {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -149,8 +225,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int huge_pmd_unshare(struct mm_struct *mm, unsigned long *addr, pte_t *ptep)
 return 0;
 }
 
-#endif
-
 #ifdef HAVE_ARCH_HUGETLB_UNMAPPED_AREA
 static unsigned long hugetlb_get_unmapped_area_bottomup(struct file *file,
 unsigned long addr, unsigned long len,
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -322,21 +396,102 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; unsigned long hugetlb_get_unmapped_area(struct file *file, unsigned long addr,
 return hugetlb_get_unmapped_area_topdown(file, addr, len,
 pgoff, flags);
 }
+#endif /* HAVE_ARCH_HUGETLB_UNMAPPED_AREA */
 
-static __init int setup_hugepagesz(char *opt)
+#ifdef CONFIG_HUGETLB_SUPER_PAGES
+static __init int __setup_hugepagesz(unsigned long ps)
 {
-unsigned long ps = memparse(opt, &amp;amp;opt);
-if (ps == PMD_SIZE) {
-hugetlb_add_hstate(PMD_SHIFT - PAGE_SHIFT);
-} else if (ps == PUD_SIZE) {
-hugetlb_add_hstate(PUD_SHIFT - PAGE_SHIFT);
+int log_ps = __builtin_ctzl(ps);
+int level, base_shift;
+
+if ((1UL &amp;lt;&amp;lt; log_ps) != ps || (log_ps &amp;amp; 1) != 0) {
+pr_warn("Not enabling %ld byte huge pages;"
+" must be a power of four.\n", ps);
+return -EINVAL;
+}
+
+if (ps &amp;gt; 64*1024*1024*1024UL) {
+pr_warn("Not enabling %ld MB huge pages;"
+" largest legal value is 64 GB .\n", ps &amp;gt;&amp;gt; 20);
+return -EINVAL;
+} else if (ps &amp;gt;= PUD_SIZE) {
+static long hv_jpage_size;
+if (hv_jpage_size == 0)
+hv_jpage_size = hv_sysconf(HV_SYSCONF_PAGE_SIZE_JUMBO);
+if (hv_jpage_size != PUD_SIZE) {
+pr_warn("Not enabling &amp;gt;= %ld MB huge pages:"
+" hypervisor reports size %ld\n",
+PUD_SIZE &amp;gt;&amp;gt; 20, hv_jpage_size);
+return -EINVAL;
+}
+level = 0;
+base_shift = PUD_SHIFT;
+} else if (ps &amp;gt;= PMD_SIZE) {
+level = 1;
+base_shift = PMD_SHIFT;
+} else if (ps &amp;gt; PAGE_SIZE) {
+level = 2;
+base_shift = PAGE_SHIFT;
 } else {
-pr_err("hugepagesz: Unsupported page size %lu M\n",
-ps &amp;gt;&amp;gt; 20);
-return 0;
+pr_err("hugepagesz: huge page size %ld too small\n", ps);
+return -EINVAL;
 }
-return 1;
+
+if (log_ps != base_shift) {
+int shift_val = log_ps - base_shift;
+if (huge_shift[level] != 0) {
+int old_shift = base_shift + huge_shift[level];
+pr_warn("Not enabling %ld MB huge pages;"
+" already have size %ld MB.\n",
+ps &amp;gt;&amp;gt; 20, (1UL &amp;lt;&amp;lt; old_shift) &amp;gt;&amp;gt; 20);
+return -EINVAL;
+}
+if (hv_set_pte_super_shift(level, shift_val) != 0) {
+pr_warn("Not enabling %ld MB huge pages;"
+" no hypervisor support.\n", ps &amp;gt;&amp;gt; 20);
+return -EINVAL;
+}
+printk(KERN_DEBUG "Enabled %ld MB huge pages\n", ps &amp;gt;&amp;gt; 20);
+huge_shift[level] = shift_val;
+}
+
+hugetlb_add_hstate(log_ps - PAGE_SHIFT);
+
+return 0;
+}
+
+static bool saw_hugepagesz;
+
+static __init int setup_hugepagesz(char *opt)
+{
+if (!saw_hugepagesz) {
+saw_hugepagesz = true;
+memset(huge_shift, 0, sizeof(huge_shift));
+}
+return __setup_hugepagesz(memparse(opt, NULL));
 }
 __setup("hugepagesz=", setup_hugepagesz);
 
-#endif /*HAVE_ARCH_HUGETLB_UNMAPPED_AREA*/
+#ifdef ADDITIONAL_HUGE_SIZE
+/*
+ * Provide an additional huge page size if no "hugepagesz" args are given.
+ * In that case, all the cores have properly set up their hv super_shift
+ * already, but we need to notify the hugetlb code to enable the
+ * new huge page size from the Linux point of view.
+ */
+static __init int add_default_hugepagesz(void)
+{
+if (!saw_hugepagesz) {
+BUILD_BUG_ON(ADDITIONAL_HUGE_SIZE &amp;gt;= PMD_SIZE ||
+     ADDITIONAL_HUGE_SIZE &amp;lt;= PAGE_SIZE);
+BUILD_BUG_ON((PAGE_SIZE &amp;lt;&amp;lt; ADDITIONAL_HUGE_SHIFT) !=
+     ADDITIONAL_HUGE_SIZE);
+BUILD_BUG_ON(ADDITIONAL_HUGE_SHIFT &amp;amp; 1);
+hugetlb_add_hstate(ADDITIONAL_HUGE_SHIFT);
+}
+return 0;
+}
+arch_initcall(add_default_hugepagesz);
+#endif
+
+#endif /* CONFIG_HUGETLB_SUPER_PAGES */
diff --git a/arch/tile/mm/init.c b/arch/tile/mm/init.c
index c04fbfd..630dd2c 100644
--- a/arch/tile/mm/init.c
+++ b/arch/tile/mm/init.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -698,6 +698,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init permanent_kmaps_init(pgd_t *pgd_base)
 #endif /* CONFIG_HIGHMEM */
 
 
+#ifndef CONFIG_64BIT
 static void __init init_free_pfn_range(unsigned long start, unsigned long end)
 {
 unsigned long pfn;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -770,6 +771,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void __init set_non_bootmem_pages_init(void)
 init_free_pfn_range(start, end);
 }
 }
+#endif
 
 /*
  * paging_init() sets up the page tables - note that all of lowmem is
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -858,8 +860,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init mem_init(void)
 /* this will put all bootmem onto the freelists */
 totalram_pages += free_all_bootmem();
 
+#ifndef CONFIG_64BIT
 /* count all remaining LOWMEM and give all HIGHMEM to page allocator */
 set_non_bootmem_pages_init();
+#endif
 
 codesize =  (unsigned long)&amp;amp;_etext - (unsigned long)&amp;amp;_text;
 datasize =  (unsigned long)&amp;amp;_end - (unsigned long)&amp;amp;_sdata;
diff --git a/arch/tile/mm/pgtable.c b/arch/tile/mm/pgtable.c
index 3d70743..345edfe 100644
--- a/arch/tile/mm/pgtable.c
+++ b/arch/tile/mm/pgtable.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -132,15 +132,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __set_fixmap(enum fixed_addresses idx, unsigned long phys, pgprot_t flags)
 set_pte_pfn(address, phys &amp;gt;&amp;gt; PAGE_SHIFT, flags);
 }
 
-#if defined(CONFIG_HIGHPTE)
-pte_t *_pte_offset_map(pmd_t *dir, unsigned long address)
-{
-pte_t *pte = kmap_atomic(pmd_page(*dir)) +
-(pmd_ptfn(*dir) &amp;lt;&amp;lt; HV_LOG2_PAGE_TABLE_ALIGN) &amp;amp; ~PAGE_MASK;
-return &amp;amp;pte[pte_index(address)];
-}
-#endif
-
 /**
  * shatter_huge_page() - ensure a given address is mapped by a small page.
  *
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -296,10 +287,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct page *pgtable_alloc_one(struct mm_struct *mm, unsigned long address,
 struct page *p;
 int i;
 
-#ifdef CONFIG_HIGHPTE
-flags |= __GFP_HIGHMEM;
-#endif
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323181">
    <title>arch/tile: support kexec() for tilegx</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323181</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=fc0c49f5db640b9dfc7bb801892b5cbb7508a76a
Commit:     fc0c49f5db640b9dfc7bb801892b5cbb7508a76a
Parent:     cd6f32aa088f4d328e676c35f51b440f2fe5b98c
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Thu Mar 29 15:48:23 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:25 2012 -0400

    arch/tile: support kexec() for tilegx
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/asm/kexec.h                      |   12 ++
 arch/tile/kernel/Makefile                          |    2 +-
 arch/tile/kernel/machine_kexec.c                   |   35 ++++-
 .../{relocate_kernel.S =&amp;gt; relocate_kernel_32.S}    |    0
 .../{relocate_kernel.S =&amp;gt; relocate_kernel_64.S}    |  150 +++++++++-----------
 5 files changed, 105 insertions(+), 94 deletions(-)

diff --git a/arch/tile/include/asm/kexec.h b/arch/tile/include/asm/kexec.h
index c11a6cc..fc98ccf 100644
--- a/arch/tile/include/asm/kexec.h
+++ b/arch/tile/include/asm/kexec.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,12 +19,24 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 #include &amp;lt;asm/page.h&amp;gt;
 
+#ifndef __tilegx__
 /* Maximum physical address we can use pages from. */
 #define KEXEC_SOURCE_MEMORY_LIMIT TASK_SIZE
 /* Maximum address we can reach in physical address mode. */
 #define KEXEC_DESTINATION_MEMORY_LIMIT TASK_SIZE
 /* Maximum address we can use for the control code buffer. */
 #define KEXEC_CONTROL_MEMORY_LIMIT TASK_SIZE
+#else
+/* We need to limit the memory below PGDIR_SIZE since
+ * we only setup page table for [0, PGDIR_SIZE) before final kexec.
+ */
+/* Maximum physical address we can use pages from. */
+#define KEXEC_SOURCE_MEMORY_LIMIT PGDIR_SIZE
+/* Maximum address we can reach in physical address mode. */
+#define KEXEC_DESTINATION_MEMORY_LIMIT PGDIR_SIZE
+/* Maximum address we can use for the control code buffer. */
+#define KEXEC_CONTROL_MEMORY_LIMIT PGDIR_SIZE
+#endif
 
 #define KEXEC_CONTROL_PAGE_SIZEPAGE_SIZE
 
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
index d6261e4..f19116d 100644
--- a/arch/tile/kernel/Makefile
+++ b/arch/tile/kernel/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -13,5 +13,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; obj-$(CONFIG_COMPAT)+= compat.o compat_signal.o
 obj-$(CONFIG_SMP)+= smpboot.o smp.o tlb.o
 obj-$(CONFIG_MODULES)+= module.o
 obj-$(CONFIG_EARLY_PRINTK)+= early_printk.o
-obj-$(CONFIG_KEXEC)+= machine_kexec.o relocate_kernel.o
+obj-$(CONFIG_KEXEC)+= machine_kexec.o relocate_kernel_$(BITS).o
 obj-$(CONFIG_PCI)+= pci.o
diff --git a/arch/tile/kernel/machine_kexec.c b/arch/tile/kernel/machine_kexec.c
index b0fa37c..f0b54a9 100644
--- a/arch/tile/kernel/machine_kexec.c
+++ b/arch/tile/kernel/machine_kexec.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,6 +31,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;asm/pgalloc.h&amp;gt;
 #include &amp;lt;asm/cacheflush.h&amp;gt;
 #include &amp;lt;asm/checksum.h&amp;gt;
+#include &amp;lt;asm/tlbflush.h&amp;gt;
+#include &amp;lt;asm/homecache.h&amp;gt;
 #include &amp;lt;hv/hypervisor.h&amp;gt;
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -222,11 +224,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct page *kimage_alloc_pages_arch(gfp_t gfp_mask, unsigned int order)
 return alloc_pages_node(0, gfp_mask, order);
 }
 
+/*
+ * Address range in which pa=va mapping is set in setup_quasi_va_is_pa().
+ * For tilepro, PAGE_OFFSET is used since this is the largest possbile value
+ * for tilepro, while for tilegx, we limit it to entire middle level page
+ * table which we assume has been allocated and is undoubtedly large enough.
+ */
+#ifndef __tilegx__
+#defineQUASI_VA_IS_PA_ADDR_RANGE PAGE_OFFSET
+#else
+#defineQUASI_VA_IS_PA_ADDR_RANGE PGDIR_SIZE
+#endif
+
 static void setup_quasi_va_is_pa(void)
 {
-HV_PTE *pgtable;
 HV_PTE pte;
-int i;
+unsigned long i;
 
 /*
  * Flush our TLB to prevent conflicts between the previous contents
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -234,16 +247,22 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static void setup_quasi_va_is_pa(void)
  */
 local_flush_tlb_all();
 
-/* setup VA is PA, at least up to PAGE_OFFSET */
-
-pgtable = (HV_PTE *)current-&amp;gt;mm-&amp;gt;pgd;
+/*
+ * setup VA is PA, at least up to QUASI_VA_IS_PA_ADDR_RANGE.
+ * Note here we assume that level-1 page table is defined by
+ * HPAGE_SIZE.
+ */
 pte = hv_pte(_PAGE_KERNEL | _PAGE_HUGE_PAGE);
 pte = hv_pte_set_mode(pte, HV_PTE_MODE_CACHE_NO_L3);
-
-for (i = 0; i &amp;lt; pgd_index(PAGE_OFFSET); i++) {
+for (i = 0; i &amp;lt; (QUASI_VA_IS_PA_ADDR_RANGE &amp;gt;&amp;gt; HPAGE_SHIFT); i++) {
+unsigned long vaddr = i &amp;lt;&amp;lt; HPAGE_SHIFT;
+pgd_t *pgd = pgd_offset(current-&amp;gt;mm, vaddr);
+pud_t *pud = pud_offset(pgd, vaddr);
+pte_t *ptep = (pte_t *) pmd_offset(pud, vaddr);
 unsigned long pfn = i &amp;lt;&amp;lt; (HPAGE_SHIFT - PAGE_SHIFT);
+
 if (pfn_valid(pfn))
-__set_pte(&amp;amp;pgtable[i], pfn_pte(pfn, pte));
+__set_pte(ptep, pfn_pte(pfn, pte));
 }
 }
 
diff --git a/arch/tile/kernel/relocate_kernel.S b/arch/tile/kernel/relocate_kernel_32.S
similarity index 100%
copy from arch/tile/kernel/relocate_kernel.S
copy to arch/tile/kernel/relocate_kernel_32.S
diff --git a/arch/tile/kernel/relocate_kernel.S b/arch/tile/kernel/relocate_kernel_64.S
similarity index 54%
rename from arch/tile/kernel/relocate_kernel.S
rename to arch/tile/kernel/relocate_kernel_64.S
index 010b418..1c09a4f 100644
--- a/arch/tile/kernel/relocate_kernel.S
+++ b/arch/tile/kernel/relocate_kernel_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1,5 +1,5 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 /*
- * Copyright 2010 Tilera Corporation. All Rights Reserved.
+ * Copyright 2011 Tilera Corporation. All Rights Reserved.
  *
  *   This program is free software; you can redistribute it and/or
  *   modify it under the terms of the GNU General Public License
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -20,15 +20,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;asm/page.h&amp;gt;
 #include &amp;lt;hv/hypervisor.h&amp;gt;
 
-#define ___hvbMEM_SV_INTRPT + HV_GLUE_START_CPA
-
-#define ___hv_dispatch(f) (___hvb + (HV_DISPATCH_ENTRY_SIZE * f))
-
-#define ___hv_console_putc ___hv_dispatch(HV_DISPATCH_CONSOLE_PUTC)
-#define ___hv_halt         ___hv_dispatch(HV_DISPATCH_HALT)
-#define ___hv_reexec       ___hv_dispatch(HV_DISPATCH_REEXEC)
-#define ___hv_flush_remote ___hv_dispatch(HV_DISPATCH_FLUSH_REMOTE)
-
 #undef RELOCATE_NEW_KERNEL_VERBOSE
 
 STD_ENTRY(relocate_new_kernel)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -37,14 +28,15 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 mover31, r1/* address of page we are on */
 mover32, r2/* start address of new kernel */
 
-shrir1, r1, PAGE_SHIFT
+shruir1, r1, PAGE_SHIFT
 addir1, r1, 1
 shlisp, r1, PAGE_SHIFT
 addisp, sp, -8
 /* we now have a stack (whether we need one or not) */
 
-movelir40, lo16(___hv_console_putc)
-aulir40, r40, ha16(___hv_console_putc)
+movelir40, hw2_last(hv_console_putc)
+shl16insli r40, r40, hw1(hv_console_putc)
+shl16insli r40, r40, hw0(hv_console_putc)
 
 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
 movelir0, 'r'
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -71,7 +63,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
  * list we are working on.
  *
  * Normally we get to the next element of the page list by
- * incrementing r30 by four.  The exception is if the element
+ * incrementing r30 by eight.  The exception is if the element
  * on the page list is an IND_INDIRECTION in which case we use
  * the element with the low bits masked off as the new value
  * of r30.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -82,13 +74,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
  * to us on the stack and make r30 point to it.
  */
 
-swsp, r30
+stsp, r30
 mover30, sp
-addisp, sp, -8
+addisp, sp, -16
 
 #if CHIP_HAS_CBOX_HOME_MAP()
 /*
- * On TILEPro, we need to flush all tiles' caches, since we may
+ * On TILE-GX, we need to flush all tiles' caches, since we may
  * have been doing hash-for-home caching there.  Note that we
  * must do this _after_ we're completely done modifying any memory
  * other than our output buffer (which we know is locally cached).
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -98,28 +90,30 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
  */
 {
  mover0, zero /* cache_pa */
- mover1, zero
+ movelir1, hw2_last(HV_FLUSH_EVICT_L2)
 }
 {
- aulir2, zero, ha16(HV_FLUSH_EVICT_L2) /* cache_control */
- moveir3, -1 /* cache_cpumask; -1 means all client tiles */
+ shl16inslir1, r1, hw1(HV_FLUSH_EVICT_L2)
+ moveir2, -1 /* cache_cpumask; -1 means all client tiles */
 }
 {
- mover4, zero /* tlb_va */
- mover5, zero /* tlb_length */
+ shl16inslir1, r1, hw0(HV_FLUSH_EVICT_L2)  /* cache_control */
+ mover3, zero /* tlb_va */
 }
 {
- mover6, zero /* tlb_pgsize */
- mover7, zero /* tlb_cpumask */
+ mover4, zero /* tlb_length */
+ mover5, zero /* tlb_pgsize */
 }
 {
- mover8, zero /* asids */
- movelir20, lo16(___hv_flush_remote)
+ mover6, zero /* tlb_cpumask */
+ mover7, zero /* asids */
 }
 {
- mover9, zero /* asidcount */
- aulir20, r20, ha16(___hv_flush_remote)
+ movelir20, hw2_last(hv_flush_remote)
+ mover8, zero /* asidcount */
 }
+shl16inslir20, r20, hw1(hv_flush_remote)
+shl16inslir20, r20, hw0(hv_flush_remote)
 
 jalrr20
 #endif
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -128,13 +122,13 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 
 movelir33, 0
 
-.Lloop:lwr10, r30
+.Lloop:ldr10, r30
 
 andir9, r10, 0xf/* low 4 bits tell us what type it is */
 xorr10, r10, r9/* r10 is now value with low 4 bits stripped */
 
-seqir0, r9, 0x1/* IND_DESTINATION */
-bztr0, .Ltry2
+cmpeqir0, r9, 0x1/* IND_DESTINATION */
+beqztr0, .Ltry2
 
 mover33, r10
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -143,12 +137,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 jalrr40
 #endif
 
-addir30, r30, 4
+addir30, r30, 8
 j.Lloop
 
 .Ltry2:
-seqir0, r9, 0x2/* IND_INDIRECTION */
-bztr0, .Ltry4
+cmpeqir0, r9, 0x2/* IND_INDIRECTION */
+beqztr0, .Ltry4
 
 mover30, r10
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -160,8 +154,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 j.Lloop
 
 .Ltry4:
-seqir0, r9, 0x4/* IND_DONE */
-bztr0, .Ltry8
+cmpeqir0, r9, 0x4/* IND_DONE */
+beqztr0, .Ltry8
 
 mf
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -173,10 +167,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 #endif
 
 mover0, r32
-movelir1, 0/* arg to hv_reexec is 64 bits */
 
-movelir41, lo16(___hv_reexec)
-aulir41, r41, ha16(___hv_reexec)
+movelir41, hw2_last(hv_reexec)
+shl16inslir41, r41, hw1(hv_reexec)
+shl16inslir41, r41, hw0(hv_reexec)
 
 jalrr41
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -189,72 +183,57 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 
 j.Lhalt
 
-.Ltry8:seqir0, r9, 0x8/* IND_SOURCE */
-bzr0, .Lerr/* unknown type */
+.Ltry8:cmpeqir0, r9, 0x8/* IND_SOURCE */
+beqzr0, .Lerr/* unknown type */
 
 /* copy page at r10 to page at r33 */
 
 mover11, r33
 
-movelir0, lo16(PAGE_SIZE)
-aulir0, r0, ha16(PAGE_SIZE)
+movelir0, hw2_last(PAGE_SIZE)
+shl16inslir0, r0, hw1(PAGE_SIZE)
+shl16inslir0, r0, hw0(PAGE_SIZE)
 addr33, r33, r0
 
 /* copy word at r10 to word at r11 until r11 equals r33 */
 
-/* We know page size must be multiple of 16, so we can unroll
- * 16 times safely without any edge case checking.
+/* We know page size must be multiple of 8, so we can unroll
+ * 8 times safely without any edge case checking.
  *
- * Issue a flush of the destination every 16 words to avoid
+ * Issue a flush of the destination every 8 words to avoid
  * incoherence when starting the new kernel.  (Now this is
  * just good paranoia because the hv_reexec call will also
  * take care of this.)
  */
 
 1:
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0; addir11, r11, 4 }
-{ lwr0, r10; addir10, r10, 4 }
-{ swr11, r0 }
-{ flush r11    ; addir11, r11, 4 }
-
-seqr0, r33, r11
-bztr0, 1b
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0; addir11, r11, 8 }
+{ ldr0, r10; addir10, r10, 8 }
+{ str11, r0 }
+{ flush r11    ; addir11, r11, 8 }
+
+cmpeqr0, r33, r11
+beqztr0, 1b
 
 #ifdef RELOCATE_NEW_KERNEL_VERBOSE
 movelir0, 's'
 jalrr40
 #endif
 
-addir30, r30, 4
+addir30, r30, 8
 j.Lloop
 
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -267,8 +246,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; STD_ENTRY(relocate_new_kernel)
 movelir0, '\n'
 jalrr40
 .Lhalt:
-movelir41, lo16(___hv_halt)
-aulir41, r41, ha16(___hv_halt)
+moveli r41, hw2_last(hv_halt)
+shl16insli r41, r41, hw1(hv_halt)
+shl16insli r41, r41, hw0(hv_halt)
 
 jalrr41
 STD_ENDPROC(relocate_new_kernel)
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323180">
    <title>tile: fix bug where fls(0) was not returning 0</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323180</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=9f1d62bed7f015d11b9164078b7fea433b474114
Commit:     9f1d62bed7f015d11b9164078b7fea433b474114
Parent:     acd1a19e002790dd127b3ff86f95a4d269e7f1d0
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Fri May 25 12:32:09 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 15:00:43 2012 -0400

    tile: fix bug where fls(0) was not returning 0
    
    This is because __builtin_clz(0) returns 64 for the "undefined" case
    of 0, since the builtin just does a right-shift 32 and "clz" instruction.
    So, use the alpha approach of casting to u32 and using __builtin_clzll().
    
    Cc: stable&amp;lt; at &amp;gt;vger.kernel.org
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/asm/bitops.h |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/arch/tile/include/asm/bitops.h b/arch/tile/include/asm/bitops.h
index 16f1fa5..bd186c4 100644
--- a/arch/tile/include/asm/bitops.h
+++ b/arch/tile/include/asm/bitops.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -77,6 +77,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int ffs(int x)
 return __builtin_ffs(x);
 }
 
+static inline int fls64(__u64 w)
+{
+return (sizeof(__u64) * 8) - __builtin_clzll(w);
+}
+
 /**
  * fls - find last set bit in word
  * &amp;lt; at &amp;gt;x: the word to search
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -90,12 +95,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int ffs(int x)
  */
 static inline int fls(int x)
 {
-return (sizeof(int) * 8) - __builtin_clz(x);
-}
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323179">
    <title>x86/mce: Add instruction recovery signatures to mce-severity table</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323179</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=37c3459b67dd5a396a968e819cf4a86d24ac9ace
Commit:     37c3459b67dd5a396a968e819cf4a86d24ac9ace
Parent:     875e26648cf9b6db9d8dc07b7959d7c61fb3f49c
Author:     Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
AuthorDate: Thu May 10 11:12:14 2012 -0700
Committer:  Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
CommitDate: Wed May 23 14:24:11 2012 -0700

    x86/mce: Add instruction recovery signatures to mce-severity table
    
    Instruction recovery cases are very similar to the data recovery one
    we already have. Just trade out for a new MCACOD value.
    
    Signed-off-by: Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
---
 arch/x86/kernel/cpu/mcheck/mce-severity.c |   10 ++++++++++
 1 files changed, 10 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
index 1ccd453..413c2ce 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -126,6 +126,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static struct severity {
 SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_DATA),
 USER
 ),
+MCESEV(
+KEEP, "HT thread notices Action required: instruction fetch error",
+SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
+MCGMASK(MCG_STATUS_EIPV, 0)
+),
+MCESEV(
+AR, "Action required: instruction fetch error",
+SER, MASK(MCI_STATUS_OVER|MCI_UC_SAR|MCI_ADDR|MCACOD, MCI_UC_SAR|MCI_ADDR|MCACOD_INSTR),
+USER
+),
 #endif
 MCESEV(
 PANIC, "Action required: unknown MCACOD",
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323178">
    <title>tile: default to tilegx_defconfig for ARCH=tile</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323178</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=1fcb78e9da714d96f65edd37b29dae3b1f7df508
Commit:     1fcb78e9da714d96f65edd37b29dae3b1f7df508
Parent:     9f1d62bed7f015d11b9164078b7fea433b474114
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Sun May 20 15:15:34 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 15:02:43 2012 -0400

    tile: default to tilegx_defconfig for ARCH=tile
    
    There is no "ARCH=tile" (just like there is no "ARCH=x86") so we need
    to pick a default configuration, either tilepro or tilegx, when users
    specify ARCH=tile.  We'll use tilegx, since that's our current chip.
    
    Reported-by: Paul Gortmaker &amp;lt;paul.gortmaker&amp;lt; at &amp;gt;windriver.com&amp;gt;
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/Makefile |    7 ++++++-
 1 files changed, 6 insertions(+), 1 deletions(-)

diff --git a/arch/tile/Makefile b/arch/tile/Makefile
index 9520bc5..e20b0a0 100644
--- a/arch/tile/Makefile
+++ b/arch/tile/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -34,7 +34,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; LIBGCC_PATH     := \
   $(shell $(CC) $(KBUILD_CFLAGS) $(KCFLAGS) -print-libgcc-file-name)
 
 # Provide the path to use for "make defconfig".
-KBUILD_DEFCONFIG := $(ARCH)_defconfig
+# We default to the newer TILE-Gx architecture if only "tile" is given.
+ifeq ($(ARCH),tile)
+        KBUILD_DEFCONFIG := tilegx_defconfig
+else
+        KBUILD_DEFCONFIG := $(ARCH)_defconfig
+endif
 
 # Used as a file extension when useful, e.g. head_$(BITS).o
 # Not needed for (e.g.) "$(CC) -m32" since the compiler automatically
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323177">
    <title>arch/tile: allow querying cpu module information from the hypervisor</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323177</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=8703d6e0fcfdcc9323d5316a443882e790efc1a6
Commit:     8703d6e0fcfdcc9323d5316a443882e790efc1a6
Parent:     b8ace0833feb308b1cb69d8b33ab08e0602dd2d2
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Fri Mar 30 16:21:17 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:28 2012 -0400

    arch/tile: allow querying cpu module information from the hypervisor
    
    This just adds a few more attributes to the information Linux
    can query from the hypervisor for the /sys/hypervisor/board/ directory,
    providing part, serial#, revision#, and description for cpu modules
    (as opposed to the board itself, or any mezzanine boards).
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/hv/hypervisor.h |   14 +++++++++++++-
 arch/tile/kernel/sysfs.c          |    8 ++++++++
 2 files changed, 21 insertions(+), 1 deletions(-)

diff --git a/arch/tile/include/hv/hypervisor.h b/arch/tile/include/hv/hypervisor.h
index 85e5cab..ccd847e 100644
--- a/arch/tile/include/hv/hypervisor.h
+++ b/arch/tile/include/hv/hypervisor.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -508,7 +508,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; typedef enum {
   HV_CONFSTR_SWITCH_CONTROL  = 14,
 
   /** Chip revision level. */
-  HV_CONFSTR_CHIP_REV        = 15
+  HV_CONFSTR_CHIP_REV        = 15,
+
+  /** CPU module part number. */
+  HV_CONFSTR_CPUMOD_PART_NUM = 16,
+
+  /** CPU module serial number. */
+  HV_CONFSTR_CPUMOD_SERIAL_NUM = 17,
+
+  /** CPU module revision level. */
+  HV_CONFSTR_CPUMOD_REV      = 18,
+
+  /** Human-readable CPU module description. */
+  HV_CONFSTR_CPUMOD_DESC     = 19
 
 } HV_ConfstrQuery;
 
diff --git a/arch/tile/kernel/sysfs.c b/arch/tile/kernel/sysfs.c
index 71ae728..e25b0a8 100644
--- a/arch/tile/kernel/sysfs.c
+++ b/arch/tile/kernel/sysfs.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -93,6 +93,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; HV_CONF_ATTR(mezz_part,HV_CONFSTR_MEZZ_PART_NUM)
 HV_CONF_ATTR(mezz_serial,HV_CONFSTR_MEZZ_SERIAL_NUM)
 HV_CONF_ATTR(mezz_revision,HV_CONFSTR_MEZZ_REV)
 HV_CONF_ATTR(mezz_description,HV_CONFSTR_MEZZ_DESC)
+HV_CONF_ATTR(cpumod_part,HV_CONFSTR_CPUMOD_PART_NUM)
+HV_CONF_ATTR(cpumod_serial,HV_CONFSTR_CPUMOD_SERIAL_NUM)
+HV_CONF_ATTR(cpumod_revision,HV_CONFSTR_CPUMOD_REV)
+HV_CONF_ATTR(cpumod_description,HV_CONFSTR_CPUMOD_DESC)
 HV_CONF_ATTR(switch_control,HV_CONFSTR_SWITCH_CONTROL)
 
 static struct attribute *board_attrs[] = {
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -104,6 +108,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static struct attribute *board_attrs[] = {
 &amp;amp;dev_attr_mezz_serial.attr,
 &amp;amp;dev_attr_mezz_revision.attr,
 &amp;amp;dev_attr_mezz_description.attr,
+&amp;amp;dev_attr_cpumod_part.attr,
+&amp;amp;dev_attr_cpumod_serial.attr,
+&amp;amp;dev_attr_cpumod_revision.attr,
+&amp;amp;dev_attr_cpumod_description.attr,
 &amp;amp;dev_attr_switch_control.attr,
 NULL
 };
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323176">
    <title>mm: add new arch_make_huge_pte() method for tile support</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323176</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=d9ed9faac283a3be73f0e11a2ef49ee55aece4db
Commit:     d9ed9faac283a3be73f0e11a2ef49ee55aece4db
Parent:     fc0c49f5db640b9dfc7bb801892b5cbb7508a76a
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Sun Apr 1 14:01:34 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:26 2012 -0400

    mm: add new arch_make_huge_pte() method for tile support
    
    The tile support for multiple-size huge pages requires tagging
    the hugetlb PTE with a "super" bit for PTEs that are multiples of
    the basic size of a pagetable span.  To set that bit properly
    we need to tweak the PTe in make_huge_pte() based on the vma.
    
    This change provides the API for a subsequent tile-specific
    change to use.
    
    Reviewed-by: Hillf Danton &amp;lt;dhillf&amp;lt; at &amp;gt;gmail.com&amp;gt;
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 include/linux/hugetlb.h |    8 ++++++++
 mm/hugetlb.c            |    1 +
 2 files changed, 9 insertions(+), 0 deletions(-)

diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 000837e..d5d6bbe 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -284,6 +284,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned int blocks_per_huge_page(struct hstate *h)
 
 #include &amp;lt;asm/hugetlb.h&amp;gt;
 
+#ifndef arch_make_huge_pte
+static inline pte_t arch_make_huge_pte(pte_t entry, struct vm_area_struct *vma,
+       struct page *page, int writable)
+{
+return entry;
+}
+#endif
+
 static inline struct hstate *page_hstate(struct page *page)
 {
 return size_to_hstate(PAGE_SIZE &amp;lt;&amp;lt; compound_order(page));
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index ae8f708..4e28416 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2213,6 +2213,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static pte_t make_huge_pte(struct vm_area_struct *vma, struct page *page,
 }
 entry = pte_mkyoung(entry);
 entry = pte_mkhuge(entry);
+entry = arch_make_huge_pte(entry, vma, page, writable);
 
 return entry;
 }
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323175">
    <title>arch/tile: mark TILEGX as not EXPERIMENTAL</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323175</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=acd1a19e002790dd127b3ff86f95a4d269e7f1d0
Commit:     acd1a19e002790dd127b3ff86f95a4d269e7f1d0
Parent:     4ce6bea220f1a40aba928bd5624ada833ee1c52b
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Sat Apr 7 15:58:24 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 15:00:39 2012 -0400

    arch/tile: mark TILEGX as not EXPERIMENTAL
    
    Also create a TILEPRO config setting to use for #ifdefs where it
    is cleaner to do so, and make the 64BIT setting depend directly
    on the setting of TILEGX.
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/Kconfig |   10 ++++------
 1 files changed, 4 insertions(+), 6 deletions(-)

diff --git a/arch/tile/Kconfig b/arch/tile/Kconfig
index cc56642..0294b21 100644
--- a/arch/tile/Kconfig
+++ b/arch/tile/Kconfig
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -117,16 +117,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; config HVC_TILE
 select HVC_DRIVER
 def_bool y
 
-# Please note: TILE-Gx support is not yet finalized; this is
-# the preliminary support.  TILE-Gx drivers are only provided
-# with the alpha or beta test versions for Tilera customers.
 config TILEGX
-depends on EXPERIMENTAL
 bool "Building with TILE-Gx (64-bit) compiler and toolchain"
 
+config TILEPRO
+def_bool !TILEGX
+
 config 64BIT
-depends on TILEGX
-def_bool y
+def_bool TILEGX
 
 config ARCH_DEFCONFIG
 string
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323174">
    <title>x86/mce: Avoid reading every machine check bank register twice.</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323174</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=95022b8cf6ed7f3292b60c8e85fe59a12bfb1c9e
Commit:     95022b8cf6ed7f3292b60c8e85fe59a12bfb1c9e
Parent:     0034102808e0dbbf3a2394b82b1bb40b5778de9e
Author:     Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
AuthorDate: Wed Apr 18 15:19:40 2012 -0700
Committer:  Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
CommitDate: Thu Apr 19 09:12:43 2012 -0700

    x86/mce: Avoid reading every machine check bank register twice.
    
    Reading machine check bank registers is slow. There is a trend of
    increasing the number of banks, and the number of cores. The main section
    of do_machine_check() is a serialized section where each cpu in turn
    checks every bank. Even on a little two socket SandyBridge-EP system
    that multiplies out as:
    
    2 sockets * 8 cores * 2 hyperthreads * 20 banks = 640 MSRs
    
    We already scan the banks in parallel in mce_no_way_out() to see if there
    is a fatal error anywhere in the system. If we build a cache of VALID
    bits during this scan, we can avoid uselessly re-reading banks that have
    no data. Note that this cache is only a hint. If the valid bit is set in a
    shared bank, all cpus that share that bank will see it during the parallel
    scan, but the first to find it in the sequential scan will (usually) clear
    the bank.
    
    Acked-by: Borislav Petkov &amp;lt;borislav.petkov&amp;lt; at &amp;gt;amd.com&amp;gt;
    Signed-off-by: Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
---
 arch/x86/kernel/cpu/mcheck/mce.c |   16 +++++++++++-----
 1 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index d086a09..66e1c51 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -641,16 +641,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; EXPORT_SYMBOL_GPL(machine_check_poll);
  * Do a quick check if any of the events requires a panic.
  * This decides if we keep the events around or clear them.
  */
-static int mce_no_way_out(struct mce *m, char **msg)
+static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp)
 {
-int i;
+int i, ret = 0;
 
 for (i = 0; i &amp;lt; banks; i++) {
 m-&amp;gt;status = mce_rdmsrl(MSR_IA32_MCx_STATUS(i));
+if (m-&amp;gt;status &amp;amp; MCI_STATUS_VAL)
+__set_bit(i, validp);
 if (mce_severity(m, tolerant, msg) &amp;gt;= MCE_PANIC_SEVERITY)
-return 1;
+ret = 1;
 }
-return 0;
+return ret;
 }
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1011,6 +1013,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void do_machine_check(struct pt_regs *regs, long error_code)
  */
 int kill_it = 0;
 DECLARE_BITMAP(toclear, MAX_NR_BANKS);
+DECLARE_BITMAP(valid_banks, MAX_NR_BANKS);
 char *msg = "Unknown";
 
 atomic_inc(&amp;amp;mce_entry);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1025,7 +1028,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void do_machine_check(struct pt_regs *regs, long error_code)
 final = &amp;amp;__get_cpu_var(mces_seen);
 *final = m;
 
-no_way_out = mce_no_way_out(&amp;amp;m, &amp;amp;msg);
+memset(valid_banks, 0, sizeof(valid_banks));
+no_way_out = mce_no_way_out(&amp;amp;m, &amp;amp;msg, valid_banks);
 
 barrier();
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1045,6 +1049,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void do_machine_check(struct pt_regs *regs, long error_code)
 order = mce_start(&amp;amp;no_way_out);
 for (i = 0; i &amp;lt; banks; i++) {
 __clear_bit(i, toclear);
+if (!test_bit(i, valid_banks))
+continue;
 if (!mce_banks[i].ctl)
 continue;
 
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323173">
    <title>MCE: Fix vm86 handling for 32bit mce handler</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323173</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=a129a7c84582629741e5fa6f40026efcd7a65bd4
Commit:     a129a7c84582629741e5fa6f40026efcd7a65bd4
Parent:     8571723a698dcc0ee16c1c63908aa99dd940ce5c
Author:     Andi Kleen &amp;lt;andi&amp;lt; at &amp;gt;firstfloor.org&amp;gt;
AuthorDate: Fri Nov 19 13:16:22 2010 +0100
Committer:  Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
CommitDate: Wed May 23 14:22:37 2012 -0700

    MCE: Fix vm86 handling for 32bit mce handler
    
    When running on 32bit the mce handler could misinterpret
    vm86 mode as ring 0. This can affect whether it does recovery
    or not; it was possible to panic when recovery was actually
    possible.
    
    Fix this by always forcing vm86 to look like ring 3.
    
    Signed-off-by: Andi Kleen &amp;lt;ak&amp;lt; at &amp;gt;linux.intel.com&amp;gt;
    Cc: &amp;lt;stable&amp;lt; at &amp;gt;vger.kernel.org&amp;gt;
    Signed-off-by: Tony Luck &amp;lt;tony.luck&amp;lt; at &amp;gt;intel.com&amp;gt;
---
 arch/x86/kernel/cpu/mcheck/mce.c |    8 ++++++++
 1 files changed, 8 insertions(+), 0 deletions(-)

diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 66e1c51..5f793e6 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -437,6 +437,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline void mce_gather_info(struct mce *m, struct pt_regs *regs)
 if (m-&amp;gt;mcgstatus &amp;amp; (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) {
 m-&amp;gt;ip = regs-&amp;gt;ip;
 m-&amp;gt;cs = regs-&amp;gt;cs;
+
+/*
+ * When in VM86 mode make the cs look like ring 3
+ * always. This is a lie, but it's better than passing
+ * the additional vm86 bit around everywhere.
+ */
+if (v8086_mode(regs))
+m-&amp;gt;cs |= 3;
 }
 /* Use accurate RIP reporting if available. */
 if (rip_msr)
--
To unsubscribe from this list: send the line "unsubscribe git-commits-head" in
the body of a message to majordomo&amp;lt; at &amp;gt;vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.linux.kernel.commits.head/323172">
    <title>arch/tile: optimize get_user/put_user and friends</title>
    <link>http://comments.gmane.org/gmane.linux.kernel.commits.head/323172</link>
    <description>&lt;pre&gt;Gitweb:     http://git.kernel.org/linus/;a=commit;h=47d632f9f8f3ed62b21f725e98b726d65769b6d7
Commit:     47d632f9f8f3ed62b21f725e98b726d65769b6d7
Parent:     1efea40d4172a2a475ccb29b59d6221e9d0c174b
Author:     Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
AuthorDate: Thu Mar 29 13:39:51 2012 -0400
Committer:  Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
CommitDate: Fri May 25 12:48:23 2012 -0400

    arch/tile: optimize get_user/put_user and friends
    
    Use direct load/store for the get_user/put_user.
    
    Previously, we would call out to a helper routine that would do the
    appropriate thing and then return, handling the possible exception
    internally.  Now we inline the load or store, along with a "we succeeded"
    indication in a register; if the load or store faults, we write a
    "we failed" indication into the same register and then return to the
    following instruction.  This is more efficient and gives us more compact
    code, as well as being more in line with what other architectures do.
    
    The special futex assembly source file for TILE-Gx also disappears in
    this change; we just use the same inlining idiom there as well, putting
    the appropriate atomic operations directly into futex_atomic_op_inuser()
    (and thus into the FUTEX_WAIT function).
    
    The underlying atomic copy_from_user, copy_to_user functions were
    renamed using the (cryptic) x86 convention as copy_from_user_ll and
    copy_to_user_ll.
    
    Signed-off-by: Chris Metcalf &amp;lt;cmetcalf&amp;lt; at &amp;gt;tilera.com&amp;gt;
---
 arch/tile/include/asm/atomic_32.h |   10 ++
 arch/tile/include/asm/futex.h     |  143 ++++++++++++++++--------
 arch/tile/include/asm/uaccess.h   |  222 ++++++++++++++++++++++---------------
 arch/tile/kernel/Makefile         |    1 -
 arch/tile/lib/atomic_32.c         |   47 +--------
 arch/tile/lib/exports.c           |    8 --
 arch/tile/lib/usercopy_32.S       |   76 -------------
 arch/tile/lib/usercopy_64.S       |   49 --------
 8 files changed, 241 insertions(+), 315 deletions(-)

diff --git a/arch/tile/include/asm/atomic_32.h b/arch/tile/include/asm/atomic_32.h
index 54d1da8..e7fb5cf 100644
--- a/arch/tile/include/asm/atomic_32.h
+++ b/arch/tile/include/asm/atomic_32.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -303,7 +303,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init_atomic_per_cpu(void);
 void __atomic_fault_unlock(int *lock_ptr);
 #endif
 
+/* Return a pointer to the lock for the given address. */
+int *__atomic_hashed_lock(volatile void *v);
+
 /* Private helper routines in lib/atomic_asm_32.S */
+struct __get_user {
+unsigned long val;
+int err;
+};
 extern struct __get_user __atomic_cmpxchg(volatile int *p,
   int *lock, int o, int n);
 extern struct __get_user __atomic_xchg(volatile int *p, int *lock, int n);
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -319,6 +326,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern u64 __atomic64_xchg_add(volatile u64 *p, int *lock, u64 n);
 extern u64 __atomic64_xchg_add_unless(volatile u64 *p,
       int *lock, u64 o, u64 n);
 
+/* Return failure from the atomic wrappers. */
+struct __get_user __atomic_bad_address(int __user *addr);
+
 #endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_TILE_ATOMIC_32_H */
diff --git a/arch/tile/include/asm/futex.h b/arch/tile/include/asm/futex.h
index d03ec12..5909ac3 100644
--- a/arch/tile/include/asm/futex.h
+++ b/arch/tile/include/asm/futex.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -28,29 +28,81 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/futex.h&amp;gt;
 #include &amp;lt;linux/uaccess.h&amp;gt;
 #include &amp;lt;linux/errno.h&amp;gt;
+#include &amp;lt;asm/atomic.h&amp;gt;
 
-extern struct __get_user futex_set(u32 __user *v, int i);
-extern struct __get_user futex_add(u32 __user *v, int n);
-extern struct __get_user futex_or(u32 __user *v, int n);
-extern struct __get_user futex_andn(u32 __user *v, int n);
-extern struct __get_user futex_cmpxchg(u32 __user *v, int o, int n);
+/*
+ * Support macros for futex operations.  Do not use these macros directly.
+ * They assume "ret", "val", "oparg", and "uaddr" in the lexical context.
+ * __futex_cmpxchg() additionally assumes "oldval".
+ */
+
+#ifdef __tilegx__
+
+#define __futex_asm(OP) \
+asm("1: {" #OP " %1, %3, %4; movei %0, 0 }\n"\
+    ".pushsection .fixup,\"ax\"\n"\
+    "0: { movei %0, %5; j 9f }\n"\
+    ".section __ex_table,\"a\"\n"\
+    ".quad 1b, 0b\n"\
+    ".popsection\n"\
+    "9:"\
+    : "=r" (ret), "=r" (val), "+m" (*(uaddr))\
+    : "r" (uaddr), "r" (oparg), "i" (-EFAULT))
+
+#define __futex_set() __futex_asm(exch4)
+#define __futex_add() __futex_asm(fetchadd4)
+#define __futex_or() __futex_asm(fetchor4)
+#define __futex_andn() ({ oparg = ~oparg; __futex_asm(fetchand4); })
+#define __futex_cmpxchg() \
+({ __insn_mtspr(SPR_CMPEXCH_VALUE, oldval); __futex_asm(cmpexch4); })
+
+#define __futex_xor()\
+({\
+u32 oldval, n = oparg;\
+if ((ret = __get_user(oldval, uaddr)) == 0) {\
+do {\
+oparg = oldval ^ n;\
+__futex_cmpxchg();\
+} while (ret == 0 &amp;amp;&amp;amp; oldval != val);\
+}\
+})
+
+/* No need to prefetch, since the atomic ops go to the home cache anyway. */
+#define __futex_prolog()
 
-#ifndef __tilegx__
-extern struct __get_user futex_xor(u32 __user *v, int n);
 #else
-static inline struct __get_user futex_xor(u32 __user *uaddr, int n)
-{
-struct __get_user asm_ret = __get_user_4(uaddr);
-if (!asm_ret.err) {
-int oldval, newval;
-do {
-oldval = asm_ret.val;
-newval = oldval ^ n;
-asm_ret = futex_cmpxchg(uaddr, oldval, newval);
-} while (asm_ret.err == 0 &amp;amp;&amp;amp; oldval != asm_ret.val);
+
+#define __futex_call(FN)\
+{\
+struct __get_user gu = FN((u32 __force *)uaddr, lock, oparg); \
+val = gu.val;\
+ret = gu.err;\
 }
-return asm_ret;
-}
+
+#define __futex_set() __futex_call(__atomic_xchg)
+#define __futex_add() __futex_call(__atomic_xchg_add)
+#define __futex_or() __futex_call(__atomic_or)
+#define __futex_andn() __futex_call(__atomic_andn)
+#define __futex_xor() __futex_call(__atomic_xor)
+
+#define __futex_cmpxchg()\
+{\
+struct __get_user gu = __atomic_cmpxchg((u32 __force *)uaddr, \
+lock, oldval, oparg); \
+val = gu.val;\
+ret = gu.err;\
+}
+
+/*
+ * Find the lock pointer for the atomic calls to use, and issue a
+ * prefetch to the user address to bring it into cache.  Similar to
+ * __atomic_setup(), but we can't do a read into the L1 since it might
+ * fault; instead we do a prefetch into the L2.
+ */
+#define __futex_prolog()\
+int *lock;\
+__insn_prefetch(uaddr);\
+lock = __atomic_hashed_lock((int __force *)uaddr)
 #endif
 
 static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -59,8 +111,12 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 int cmp = (encoded_op &amp;gt;&amp;gt; 24) &amp;amp; 15;
 int oparg = (encoded_op &amp;lt;&amp;lt; 8) &amp;gt;&amp;gt; 20;
 int cmparg = (encoded_op &amp;lt;&amp;lt; 20) &amp;gt;&amp;gt; 20;
-int ret;
-struct __get_user asm_ret;
+int uninitialized_var(val), ret;
+
+__futex_prolog();
+
+/* The 32-bit futex code makes this assumption, so validate it here. */
+BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 
 if (encoded_op &amp;amp; (FUTEX_OP_OPARG_SHIFT &amp;lt;&amp;lt; 28))
 oparg = 1 &amp;lt;&amp;lt; oparg;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -71,46 +127,45 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 pagefault_disable();
 switch (op) {
 case FUTEX_OP_SET:
-asm_ret = futex_set(uaddr, oparg);
+__futex_set();
 break;
 case FUTEX_OP_ADD:
-asm_ret = futex_add(uaddr, oparg);
+__futex_add();
 break;
 case FUTEX_OP_OR:
-asm_ret = futex_or(uaddr, oparg);
+__futex_or();
 break;
 case FUTEX_OP_ANDN:
-asm_ret = futex_andn(uaddr, oparg);
+__futex_andn();
 break;
 case FUTEX_OP_XOR:
-asm_ret = futex_xor(uaddr, oparg);
+__futex_xor();
 break;
 default:
-asm_ret.err = -ENOSYS;
+ret = -ENOSYS;
+break;
 }
 pagefault_enable();
 
-ret = asm_ret.err;
-
 if (!ret) {
 switch (cmp) {
 case FUTEX_OP_CMP_EQ:
-ret = (asm_ret.val == cmparg);
+ret = (val == cmparg);
 break;
 case FUTEX_OP_CMP_NE:
-ret = (asm_ret.val != cmparg);
+ret = (val != cmparg);
 break;
 case FUTEX_OP_CMP_LT:
-ret = (asm_ret.val &amp;lt; cmparg);
+ret = (val &amp;lt; cmparg);
 break;
 case FUTEX_OP_CMP_GE:
-ret = (asm_ret.val &amp;gt;= cmparg);
+ret = (val &amp;gt;= cmparg);
 break;
 case FUTEX_OP_CMP_LE:
-ret = (asm_ret.val &amp;lt;= cmparg);
+ret = (val &amp;lt;= cmparg);
 break;
 case FUTEX_OP_CMP_GT:
-ret = (asm_ret.val &amp;gt; cmparg);
+ret = (val &amp;gt; cmparg);
 break;
 default:
 ret = -ENOSYS;
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -120,22 +175,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
 }
 
 static inline int futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
-u32 oldval, u32 newval)
+u32 oldval, u32 oparg)
 {
-struct __get_user asm_ret;
+int ret, val;
+
+__futex_prolog();
 
 if (!access_ok(VERIFY_WRITE, uaddr, sizeof(u32)))
 return -EFAULT;
 
-asm_ret = futex_cmpxchg(uaddr, oldval, newval);
-*uval = asm_ret.val;
-return asm_ret.err;
-}
+__futex_cmpxchg();
 
-#ifndef __tilegx__
-/* Return failure from the atomic wrappers. */
-struct __get_user __atomic_bad_address(int __user *addr);
-#endif
+*uval = val;
+return ret;
+}
 
 #endif /* !__ASSEMBLY__ */
 
diff --git a/arch/tile/include/asm/uaccess.h b/arch/tile/include/asm/uaccess.h
index ef34d2c..c3dd275 100644
--- a/arch/tile/include/asm/uaccess.h
+++ b/arch/tile/include/asm/uaccess.h
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -114,45 +114,75 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; struct exception_table_entry {
 extern int fixup_exception(struct pt_regs *regs);
 
 /*
- * We return the __get_user_N function results in a structure,
- * thus in r0 and r1.  If "err" is zero, "val" is the result
- * of the read; otherwise, "err" is -EFAULT.
- *
- * We rarely need 8-byte values on a 32-bit architecture, but
- * we size the structure to accommodate.  In practice, for the
- * the smaller reads, we can zero the high word for free, and
- * the caller will ignore it by virtue of casting anyway.
+ * Support macros for __get_user().
+ *
+ * Implementation note: The "case 8" logic of casting to the type of
+ * the result of subtracting the value from itself is basically a way
+ * of keeping all integer types the same, but casting any pointers to
+ * ptrdiff_t, i.e. also an integer type.  This way there are no
+ * questionable casts seen by the compiler on an ILP32 platform.
+ *
+ * Note that __get_user() and __put_user() assume proper alignment.
  */
-struct __get_user {
-unsigned long long val;
-int err;
-};
 
-/*
- * FIXME: we should express these as inline extended assembler, since
- * they're fundamentally just a variable dereference and some
- * supporting exception_table gunk.  Note that (a la i386) we can
- * extend the copy_to_user and copy_from_user routines to call into
- * such extended assembler routines, though we will have to use a
- * different return code in that case (1, 2, or 4, rather than -EFAULT).
- */
-extern struct __get_user __get_user_1(const void __user *);
-extern struct __get_user __get_user_2(const void __user *);
-extern struct __get_user __get_user_4(const void __user *);
-extern struct __get_user __get_user_8(const void __user *);
-extern int __put_user_1(long, void __user *);
-extern int __put_user_2(long, void __user *);
-extern int __put_user_4(long, void __user *);
-extern int __put_user_8(long long, void __user *);
-
-/* Unimplemented routines to cause linker failures */
-extern struct __get_user __get_user_bad(void);
-extern int __put_user_bad(void);
+#ifdef __LP64__
+#define _ASM_PTR".quad"
+#else
+#define _ASM_PTR".long"
+#endif
+
+#define __get_user_asm(OP, x, ptr, ret)\
+asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n"\
+     ".pushsection .fixup,\"ax\"\n"\
+     "0: { movei %1, 0; movei %0, %3 }\n"\
+     "j 9f\n"\
+     ".section __ex_table,\"a\"\n"\
+     _ASM_PTR " 1b, 0b\n"\
+     ".popsection\n"\
+     "9:"\
+     : "=r" (ret), "=r" (x)\
+     : "r" (ptr), "i" (-EFAULT))
+
+#ifdef __tilegx__
+#define __get_user_1(x, ptr, ret) __get_user_asm(ld1u, x, ptr, ret)
+#define __get_user_2(x, ptr, ret) __get_user_asm(ld2u, x, ptr, ret)
+#define __get_user_4(x, ptr, ret) __get_user_asm(ld4u, x, ptr, ret)
+#define __get_user_8(x, ptr, ret) __get_user_asm(ld, x, ptr, ret)
+#else
+#define __get_user_1(x, ptr, ret) __get_user_asm(lb_u, x, ptr, ret)
+#define __get_user_2(x, ptr, ret) __get_user_asm(lh_u, x, ptr, ret)
+#define __get_user_4(x, ptr, ret) __get_user_asm(lw, x, ptr, ret)
+#ifdef __LITTLE_ENDIAN
+#define __lo32(a, b) a
+#define __hi32(a, b) b
+#else
+#define __lo32(a, b) b
+#define __hi32(a, b) a
+#endif
+#define __get_user_8(x, ptr, ret)\
+({\
+unsigned int __a, __b;\
+asm volatile("1: { lw %1, %3; addi %2, %3, 4 }\n"\
+     "2: { lw %2, %2; movei %0, 0 }\n"\
+     ".pushsection .fixup,\"ax\"\n"\
+     "0: { movei %1, 0; movei %2, 0 }\n"\
+     "{ movei %0, %4; j 9f }\n"\
+     ".section __ex_table,\"a\"\n"\
+     ".word 1b, 0b\n"\
+     ".word 2b, 0b\n"\
+     ".popsection\n"\
+     "9:"\
+     : "=r" (ret), "=r" (__a), "=&amp;amp;r" (__b)\
+     : "r" (ptr), "i" (-EFAULT));\
+(x) = (__typeof(x))(__typeof((x)-(x)))\
+(((u64)__hi32(__a, __b) &amp;lt;&amp;lt; 32) |\
+ __lo32(__a, __b));\
+})
+#endif
+
+extern int __get_user_bad(void)
+  __attribute__((warning("sizeof __get_user argument not 1, 2, 4 or 8")));
 
-/*
- * Careful: we have to cast the result to the type of the pointer
- * for sign reasons.
- */
 /**
  * __get_user: - Get a simple variable from user space, with less checking.
  * &amp;lt; at &amp;gt;x:   Variable to store result.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -174,30 +204,62 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern int __put_user_bad(void);
  * function.
  */
 #define __get_user(x, ptr)\
-({struct __get_user __ret;\
-__typeof__(*(ptr)) const __user *__gu_addr = (ptr);\
-__chk_user_ptr(__gu_addr);\
-switch (sizeof(*(__gu_addr))) {\
-case 1:\
-__ret = __get_user_1(__gu_addr);\
-break;\
-case 2:\
-__ret = __get_user_2(__gu_addr);\
-break;\
-case 4:\
-__ret = __get_user_4(__gu_addr);\
-break;\
-case 8:\
-__ret = __get_user_8(__gu_addr);\
-break;\
-default:\
-__ret = __get_user_bad();\
-break;\
-}\
-(x) = (__typeof__(*__gu_addr)) (__typeof__(*__gu_addr - *__gu_addr)) \
-  __ret.val;                                \
-__ret.err;\
-})
+({\
+int __ret;\
+__chk_user_ptr(ptr);\
+switch (sizeof(*(ptr))) {\
+case 1: __get_user_1(x, ptr, __ret); break;\
+case 2: __get_user_2(x, ptr, __ret); break;\
+case 4: __get_user_4(x, ptr, __ret); break;\
+case 8: __get_user_8(x, ptr, __ret); break;\
+default: __ret = __get_user_bad(); break;\
+}\
+__ret;\
+})
+
+/* Support macros for __put_user(). */
+
+#define __put_user_asm(OP, x, ptr, ret)\
+asm volatile("1: {" #OP " %1, %2; movei %0, 0 }\n"\
+     ".pushsection .fixup,\"ax\"\n"\
+     "0: { movei %0, %3; j 9f }\n"\
+     ".section __ex_table,\"a\"\n"\
+     _ASM_PTR " 1b, 0b\n"\
+     ".popsection\n"\
+     "9:"\
+     : "=r" (ret)\
+     : "r" (ptr), "r" (x), "i" (-EFAULT))
+
+#ifdef __tilegx__
+#define __put_user_1(x, ptr, ret) __put_user_asm(st1, x, ptr, ret)
+#define __put_user_2(x, ptr, ret) __put_user_asm(st2, x, ptr, ret)
+#define __put_user_4(x, ptr, ret) __put_user_asm(st4, x, ptr, ret)
+#define __put_user_8(x, ptr, ret) __put_user_asm(st, x, ptr, ret)
+#else
+#define __put_user_1(x, ptr, ret) __put_user_asm(sb, x, ptr, ret)
+#define __put_user_2(x, ptr, ret) __put_user_asm(sh, x, ptr, ret)
+#define __put_user_4(x, ptr, ret) __put_user_asm(sw, x, ptr, ret)
+#define __put_user_8(x, ptr, ret)\
+({\
+u64 __x = (__typeof((x)-(x)))(x);\
+int __lo = (int) __x, __hi = (int) (__x &amp;gt;&amp;gt; 32);\
+asm volatile("1: { sw %1, %2; addi %0, %1, 4 }\n"\
+     "2: { sw %0, %3; movei %0, 0 }\n"\
+     ".pushsection .fixup,\"ax\"\n"\
+     "0: { movei %0, %4; j 9f }\n"\
+     ".section __ex_table,\"a\"\n"\
+     ".word 1b, 0b\n"\
+     ".word 2b, 0b\n"\
+     ".popsection\n"\
+     "9:"\
+     : "=&amp;amp;r" (ret)\
+     : "r" (ptr), "r" (__lo32(__lo, __hi)),\
+     "r" (__hi32(__lo, __hi)), "i" (-EFAULT));\
+})
+#endif
+
+extern int __put_user_bad(void)
+  __attribute__((warning("sizeof __put_user argument not 1, 2, 4 or 8")));
 
 /**
  * __put_user: - Write a simple value into user space, with less checking.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -217,39 +279,19 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; extern int __put_user_bad(void);
  * function.
  *
  * Returns zero on success, or -EFAULT on error.
- *
- * Implementation note: The "case 8" logic of casting to the type of
- * the result of subtracting the value from itself is basically a way
- * of keeping all integer types the same, but casting any pointers to
- * ptrdiff_t, i.e. also an integer type.  This way there are no
- * questionable casts seen by the compiler on an ILP32 platform.
  */
 #define __put_user(x, ptr)\
 ({\
-int __pu_err = 0;\
-__typeof__(*(ptr)) __user *__pu_addr = (ptr);\
-typeof(*__pu_addr) __pu_val = (x);\
-__chk_user_ptr(__pu_addr);\
-switch (sizeof(__pu_val)) {\
-case 1:\
-__pu_err = __put_user_1((long)__pu_val, __pu_addr);\
-break;\
-case 2:\
-__pu_err = __put_user_2((long)__pu_val, __pu_addr);\
-break;\
-case 4:\
-__pu_err = __put_user_4((long)__pu_val, __pu_addr);\
-break;\
-case 8:\
-__pu_err =\
-  __put_user_8((__typeof__(__pu_val - __pu_val))__pu_val,\
-__pu_addr);\
-break;\
-default:\
-__pu_err = __put_user_bad();\
-break;\
+int __ret;\
+__chk_user_ptr(ptr);\
+switch (sizeof(*(ptr))) {\
+case 1: __put_user_1(x, ptr, __ret); break;\
+case 2: __put_user_2(x, ptr, __ret); break;\
+case 4: __put_user_4(x, ptr, __ret); break;\
+case 8: __put_user_8(x, ptr, __ret); break;\
+default: __ret = __put_user_bad(); break;\
 }\
-__pu_err;\
+__ret;\
 })
 
 /*
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -378,7 +420,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; static inline unsigned long __must_check copy_from_user(void *to,
 /**
  * __copy_in_user() - copy data within user space, with less checking.
  * &amp;lt; at &amp;gt;to:   Destination address, in user space.
- * &amp;lt; at &amp;gt;from: Source address, in kernel space.
+ * &amp;lt; at &amp;gt;from: Source address, in user space.
  * &amp;lt; at &amp;gt;n:    Number of bytes to copy.
  *
  * Context: User context only.  This function may sleep.
diff --git a/arch/tile/kernel/Makefile b/arch/tile/kernel/Makefile
index b4dbc05..d6261e4 100644
--- a/arch/tile/kernel/Makefile
+++ b/arch/tile/kernel/Makefile
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9,7 +9,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; obj-y := backtrace.o entry.o init_task.o irq.o messaging.o \
 intvec_$(BITS).o regs_$(BITS).o tile-desc_$(BITS).o
 
 obj-$(CONFIG_HARDWALL)+= hardwall.o
-obj-$(CONFIG_TILEGX)+= futex_64.o
 obj-$(CONFIG_COMPAT)+= compat.o compat_signal.o
 obj-$(CONFIG_SMP)+= smpboot.o smp.o tlb.o
 obj-$(CONFIG_MODULES)+= module.o
diff --git a/arch/tile/lib/atomic_32.c b/arch/tile/lib/atomic_32.c
index 771b251..f5cada7 100644
--- a/arch/tile/lib/atomic_32.c
+++ b/arch/tile/lib/atomic_32.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -18,7 +18,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 #include &amp;lt;linux/module.h&amp;gt;
 #include &amp;lt;linux/mm.h&amp;gt;
 #include &amp;lt;linux/atomic.h&amp;gt;
-#include &amp;lt;asm/futex.h&amp;gt;
 #include &amp;lt;arch/chip.h&amp;gt;
 
 /* See &amp;lt;asm/atomic_32.h&amp;gt; */
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -50,7 +49,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; int atomic_locks[PAGE_SIZE / sizeof(int)] __page_aligned_bss;
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
 
-static inline int *__atomic_hashed_lock(volatile void *v)
+int *__atomic_hashed_lock(volatile void *v)
 {
 /* NOTE: this code must match "sys_cmpxchg" in kernel/intvec_32.S */
 #if ATOMIC_LOCKS_FOUND_VIA_TABLE()
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -191,47 +190,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; u64 _atomic64_cmpxchg(atomic64_t *v, u64 o, u64 n)
 EXPORT_SYMBOL(_atomic64_cmpxchg);
 
 
-static inline int *__futex_setup(int __user *v)
-{
-/*
- * Issue a prefetch to the counter to bring it into cache.
- * As for __atomic_setup, but we can't do a read into the L1
- * since it might fault; instead we do a prefetch into the L2.
- */
-__insn_prefetch(v);
-return __atomic_hashed_lock((int __force *)v);
-}
-
-struct __get_user futex_set(u32 __user *v, int i)
-{
-return __atomic_xchg((int __force *)v, __futex_setup(v), i);
-}
-
-struct __get_user futex_add(u32 __user *v, int n)
-{
-return __atomic_xchg_add((int __force *)v, __futex_setup(v), n);
-}
-
-struct __get_user futex_or(u32 __user *v, int n)
-{
-return __atomic_or((int __force *)v, __futex_setup(v), n);
-}
-
-struct __get_user futex_andn(u32 __user *v, int n)
-{
-return __atomic_andn((int __force *)v, __futex_setup(v), n);
-}
-
-struct __get_user futex_xor(u32 __user *v, int n)
-{
-return __atomic_xor((int __force *)v, __futex_setup(v), n);
-}
-
-struct __get_user futex_cmpxchg(u32 __user *v, int o, int n)
-{
-return __atomic_cmpxchg((int __force *)v, __futex_setup(v), o, n);
-}
-
 /*
  * If any of the atomic or futex routines hit a bad address (not in
  * the page tables at kernel PL) this routine is called.  The futex
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -323,7 +281,4 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt; void __init __init_atomic_per_cpu(void)
 BUILD_BUG_ON((PAGE_SIZE &amp;gt;&amp;gt; 3) &amp;gt; ATOMIC_HASH_SIZE);
 
 #endif /* ATOMIC_LOCKS_FOUND_VIA_TABLE() */
-
-/* The futex code makes this assumption, so we validate it here. */
-BUILD_BUG_ON(sizeof(atomic_t) != sizeof(int));
 }
diff --git a/arch/tile/lib/exports.c b/arch/tile/lib/exports.c
index 2a81d32..dd5f0a3 100644
--- a/arch/tile/lib/exports.c
+++ b/arch/tile/lib/exports.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -18,14 +18,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 /* arch/tile/lib/usercopy.S */
 #include &amp;lt;linux/uaccess.h&amp;gt;
-EXPORT_SYMBOL(__get_user_1);
-EXPORT_SYMBOL(__get_user_2);
-EXPORT_SYMBOL(__get_user_4);
-EXPORT_SYMBOL(__get_user_8);
-EXPORT_SYMBOL(__put_user_1);
-EXPORT_SYMBOL(__put_user_2);
-EXPORT_SYMBOL(__put_user_4);
-EXPORT_SYMBOL(__put_user_8);
 EXPORT_SYMBOL(strnlen_user_asm);
 EXPORT_SYMBOL(strncpy_from_user_asm);
 EXPORT_SYMBOL(clear_user_asm);
diff --git a/arch/tile/lib/usercopy_32.S b/arch/tile/lib/usercopy_32.S
index 979f76d..b62d002 100644
--- a/arch/tile/lib/usercopy_32.S
+++ b/arch/tile/lib/usercopy_32.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,82 +19,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 /* Access user memory, but use MMU to avoid propagating kernel exceptions. */
 
-.pushsection .fixup,"ax"
-
-get_user_fault:
-{ move r0, zero; move r1, zero }
-{ movei r2, -EFAULT; jrp lr }
-ENDPROC(get_user_fault)
-
-put_user_fault:
-{ movei r0, -EFAULT; jrp lr }
-ENDPROC(put_user_fault)
-
-.popsection
-
-/*
- * __get_user_N functions take a pointer in r0, and return 0 in r2
- * on success, with the value in r0; or else -EFAULT in r2.
- */
-#define __get_user_N(bytes, LOAD) \
-STD_ENTRY(__get_user_##bytes); \
-1:{ LOAD r0, r0; move r1, zero; move r2, zero }; \
-jrp lr; \
-STD_ENDPROC(__get_user_##bytes); \
-.pushsection __ex_table,"a"; \
-.word 1b, get_user_fault; \
-.popsection
-
-__get_user_N(1, lb_u)
-__get_user_N(2, lh_u)
-__get_user_N(4, lw)
-
-/*
- * __get_user_8 takes a pointer in r0, and returns 0 in r2
- * on success, with the value in r0/r1; or else -EFAULT in r2.
- */
-STD_ENTRY(__get_user_8);
-1:{ lw r0, r0; addi r1, r0, 4 };
-2:{ lw r1, r1; move r2, zero };
-jrp lr;
-STD_ENDPROC(__get_user_8);
-.pushsection __ex_table,"a";
-.word 1b, get_user_fault;
-.word 2b, get_user_fault;
-.popsection
-
-/*
- * __put_user_N functions take a value in r0 and a pointer in r1,
- * and return 0 in r0 on success or -EFAULT on failure.
- */
-#define __put_user_N(bytes, STORE) \
-STD_ENTRY(__put_user_##bytes); \
-1:{ STORE r1, r0; move r0, zero }; \
-jrp lr; \
-STD_ENDPROC(__put_user_##bytes); \
-.pushsection __ex_table,"a"; \
-.word 1b, put_user_fault; \
-.popsection
-
-__put_user_N(1, sb)
-__put_user_N(2, sh)
-__put_user_N(4, sw)
-
-/*
- * __put_user_8 takes a value in r0/r1 and a pointer in r2,
- * and returns 0 in r0 on success or -EFAULT on failure.
- */
-STD_ENTRY(__put_user_8)
-1:      { sw r2, r0; addi r2, r2, 4 }
-2:      { sw r2, r1; move r0, zero }
-jrp lr
-STD_ENDPROC(__put_user_8)
-.pushsection __ex_table,"a"
-.word 1b, put_user_fault
-.word 2b, put_user_fault
-.popsection
-
-
 /*
  * strnlen_user_asm takes the pointer in r0, and the length bound in r1.
  * It returns the length, including the terminating NUL, or zero on exception.
diff --git a/arch/tile/lib/usercopy_64.S b/arch/tile/lib/usercopy_64.S
index 2ff44f8..adb2dbb 100644
--- a/arch/tile/lib/usercopy_64.S
+++ b/arch/tile/lib/usercopy_64.S
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -19,55 +19,6 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 /* Access user memory, but use MMU to avoid propagating kernel exceptions. */
 
-.pushsection .fixup,"ax"
-
-get_user_fault:
-{ movei r1, -EFAULT; move r0, zero }
-jrp lr
-ENDPROC(get_user_fault)
-
-put_user_fault:
-{ movei r0, -EFAULT; jrp lr }
-ENDPROC(put_user_fault)
-
-.popsection
-
-/*
- * __get_user_N functions take a pointer in r0, and return 0 in r1
- * on success, with the value in r0; or else -EFAULT in r1.
- */
-#define __get_user_N(bytes, LOAD) \
-STD_ENTRY(__get_user_##bytes); \
-1:{ LOAD r0, r0; move r1, zero }; \
-jrp lr; \
-STD_ENDPROC(__get_user_##bytes); \
-.pushsection __ex_table,"a"; \
-.quad 1b, get_user_fault; \
-.popsection
-
-__get_user_N(1, ld1u)
-__get_user_N(2, ld2u)
-__get_user_N(4, ld4u)
-__get_user_N(8, ld)
-
-/*
- * __put_user_N functions take a value in r0 and a pointer in r1,
- * and return 0 in r0 on success or -EFAULT on failure.
- */
-#define __put_user_N(bytes, STORE) \
-STD_ENTRY(__put_user_##bytes); \
-1:{ STORE r1, r0; move r0, zero }; \
-jrp lr; \
-STD_ENDPROC(__put_user_##bytes); \
-.pushsection __ex_table,"a"; \
-.quad 1b, put_user_fault; \
-.popsection
-
-__put_user_N(1, st1)
-__put_user_N(2, st2)
-__put_user_N(4, st4)
-__put_user_N(8, st)
&lt;/pre&gt;</description>
    <dc:creator>Linux Kernel Mailing List</dc:creator>
    <dc:date>2012-05-25T23:37:54</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.linux.kernel.commits.head">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.linux.kernel.commits.head</link>
  </textinput>
</rdf:RDF>

