diff options
author | Paul Mackerras <paulus@samba.org> | 2007-09-20 10:09:27 +1000 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2007-09-20 10:09:27 +1000 |
commit | 0ce49a3945474fc942ec37c0c0efece60f592f80 (patch) | |
tree | f42b821b2d9e2d8775bc22f56d444c2cc7b7b7dd /include | |
parent | 9e4859ef5462193643fd2b3c8ffb298e5a4a4319 (diff) | |
parent | a88a8eff1e6e32d3288986a9d36c6a449c032d3a (diff) |
Merge branch 'linux-2.6'
Diffstat (limited to 'include')
31 files changed, 711 insertions, 352 deletions
diff --git a/include/asm-blackfin/mach-bf561/cdefBF561.h b/include/asm-blackfin/mach-bf561/cdefBF561.h index 6e87ab269ff..73d4d65249c 100644 --- a/include/asm-blackfin/mach-bf561/cdefBF561.h +++ b/include/asm-blackfin/mach-bf561/cdefBF561.h @@ -83,9 +83,9 @@ static __inline__ void bfin_write_VR_CTL(unsigned int val) /* For MMR's that are reserved on Core B, set up defines to better integrate with other ports */ #define bfin_read_SWRST() bfin_read_SICA_SWRST() -#define bfin_write_SWRST() bfin_write_SICA_SWRST() +#define bfin_write_SWRST(val) bfin_write_SICA_SWRST(val) #define bfin_read_SYSCR() bfin_read_SICA_SYSCR() -#define bfin_write_SYSCR() bfin_write_SICA_SYSCR() +#define bfin_write_SYSCR(val) bfin_write_SICA_SYSCR(val) /* System Reset and Interrupt Controller registers for core A (0xFFC0 0100-0xFFC0 01FF) */ #define bfin_read_SICA_SWRST() bfin_read16(SICA_SWRST) diff --git a/include/asm-blackfin/string.h b/include/asm-blackfin/string.h index 6f1eb7d6d3c..e8ada91ab00 100644 --- a/include/asm-blackfin/string.h +++ b/include/asm-blackfin/string.h @@ -9,13 +9,16 @@ extern inline char *strcpy(char *dest, const char *src) char *xdest = dest; char temp = 0; - __asm__ __volatile__ - ("1:\t%2 = B [%1++] (Z);\n\t" - "B [%0++] = %2;\n\t" - "CC = %2;\n\t" - "if cc jump 1b (bp);\n" - : "+&a" (dest), "+&a" (src), "=&d" (temp) - ::"memory", "CC"); + __asm__ __volatile__ ( + "1:" + "%2 = B [%1++] (Z);" + "B [%0++] = %2;" + "CC = %2;" + "if cc jump 1b (bp);" + : "+&a" (dest), "+&a" (src), "=&d" (temp) + : + : "memory", "CC"); + return xdest; } @@ -28,37 +31,56 @@ extern inline char *strncpy(char *dest, const char *src, size_t n) if (n == 0) return xdest; - __asm__ __volatile__ - ("1:\t%3 = B [%1++] (Z);\n\t" - "B [%0++] = %3;\n\t" - "CC = %3;\n\t" - "if ! cc jump 2f;\n\t" - "%2 += -1;\n\t" - "CC = %2 == 0;\n\t" - "if ! cc jump 1b (bp);\n" - "2:\n" - : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp) - ::"memory", "CC"); + __asm__ __volatile__ ( + "1:" + "%3 = B [%1++] (Z);" + "B [%0++] = %3;" + "CC = %3;" + "if ! cc jump 2f;" + "%2 += -1;" + "CC = %2 == 0;" + "if ! cc jump 1b (bp);" + "jump 4f;" + "2:" + /* if src is shorter than n, we need to null pad bytes now */ + "%3 = 0;" + "3:" + "%2 += -1;" + "CC = %2 == 0;" + "if cc jump 4f;" + "B [%0++] = %3;" + "jump 3b;" + "4:" + : "+&a" (dest), "+&a" (src), "+&da" (n), "=&d" (temp) + : + : "memory", "CC"); + return xdest; } #define __HAVE_ARCH_STRCMP extern inline int strcmp(const char *cs, const char *ct) { - char __res1, __res2; - - __asm__ - ("1:\t%2 = B[%0++] (Z);\n\t" /* get *cs */ - "%3 = B[%1++] (Z);\n\t" /* get *ct */ - "CC = %2 == %3;\n\t" /* compare a byte */ - "if ! cc jump 2f;\n\t" /* not equal, break out */ - "CC = %2;\n\t" /* at end of cs? */ - "if cc jump 1b (bp);\n\t" /* no, keep going */ - "jump.s 3f;\n" /* strings are equal */ - "2:\t%2 = %2 - %3;\n" /* *cs - *ct */ - "3:\n" - : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2) - : : "CC"); + /* need to use int's here so the char's in the assembly don't get + * sign extended incorrectly when we don't want them to be + */ + int __res1, __res2; + + __asm__ __volatile__ ( + "1:" + "%2 = B[%0++] (Z);" /* get *cs */ + "%3 = B[%1++] (Z);" /* get *ct */ + "CC = %2 == %3;" /* compare a byte */ + "if ! cc jump 2f;" /* not equal, break out */ + "CC = %2;" /* at end of cs? */ + "if cc jump 1b (bp);" /* no, keep going */ + "jump.s 3f;" /* strings are equal */ + "2:" + "%2 = %2 - %3;" /* *cs - *ct */ + "3:" + : "+&a" (cs), "+&a" (ct), "=&d" (__res1), "=&d" (__res2) + : + : "memory", "CC"); return __res1; } @@ -66,26 +88,35 @@ extern inline int strcmp(const char *cs, const char *ct) #define __HAVE_ARCH_STRNCMP extern inline int strncmp(const char *cs, const char *ct, size_t count) { - char __res1, __res2; + /* need to use int's here so the char's in the assembly don't get + * sign extended incorrectly when we don't want them to be + */ + int __res1, __res2; if (!count) return 0; - __asm__ - ("1:\t%3 = B[%0++] (Z);\n\t" /* get *cs */ - "%4 = B[%1++] (Z);\n\t" /* get *ct */ - "CC = %3 == %4;\n\t" /* compare a byte */ - "if ! cc jump 3f;\n\t" /* not equal, break out */ - "CC = %3;\n\t" /* at end of cs? */ - "if ! cc jump 4f;\n\t" /* yes, all done */ - "%2 += -1;\n\t" /* no, adjust count */ - "CC = %2 == 0;\n\t" - "if ! cc jump 1b;\n" /* more to do, keep going */ - "2:\t%3 = 0;\n\t" /* strings are equal */ - "jump.s 4f;\n" - "3:\t%3 = %3 - %4;\n" /* *cs - *ct */ - "4:" - : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2) - : : "CC"); + + __asm__ __volatile__ ( + "1:" + "%3 = B[%0++] (Z);" /* get *cs */ + "%4 = B[%1++] (Z);" /* get *ct */ + "CC = %3 == %4;" /* compare a byte */ + "if ! cc jump 3f;" /* not equal, break out */ + "CC = %3;" /* at end of cs? */ + "if ! cc jump 4f;" /* yes, all done */ + "%2 += -1;" /* no, adjust count */ + "CC = %2 == 0;" + "if ! cc jump 1b;" /* more to do, keep going */ + "2:" + "%3 = 0;" /* strings are equal */ + "jump.s 4f;" + "3:" + "%3 = %3 - %4;" /* *cs - *ct */ + "4:" + : "+&a" (cs), "+&a" (ct), "+&da" (count), "=&d" (__res1), "=&d" (__res2) + : + : "memory", "CC"); + return __res1; } diff --git a/include/asm-mips/compiler.h b/include/asm-mips/compiler.h index 169ae26105e..aa6b876bbd7 100644 --- a/include/asm-mips/compiler.h +++ b/include/asm-mips/compiler.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2004 Maciej W. Rozycki + * Copyright (C) 2004, 2007 Maciej W. Rozycki * * This file is subject to the terms and conditions of the GNU General Public * License. See the file "COPYING" in the main directory of this archive @@ -9,8 +9,10 @@ #define _ASM_COMPILER_H #if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) +#define GCC_IMM_ASM "n" #define GCC_REG_ACCUM "$0" #else +#define GCC_IMM_ASM "rn" #define GCC_REG_ACCUM "accum" #endif diff --git a/include/asm-mips/mach-generic/ide.h b/include/asm-mips/mach-generic/ide.h index 2b928577be5..a77128362a7 100644 --- a/include/asm-mips/mach-generic/ide.h +++ b/include/asm-mips/mach-generic/ide.h @@ -29,6 +29,35 @@ #define IDE_ARCH_OBSOLETE_DEFAULTS +static __inline__ int ide_probe_legacy(void) +{ +#ifdef CONFIG_PCI + struct pci_dev *dev; + /* + * This can be called on the ide_setup() path, super-early in + * boot. But the down_read() will enable local interrupts, + * which can cause some machines to crash. So here we detect + * and flag that situation and bail out early. + */ + if (no_pci_devices()) + return 0; + dev = pci_get_class(PCI_CLASS_BRIDGE_EISA << 8, NULL); + if (dev) + goto found; + dev = pci_get_class(PCI_CLASS_BRIDGE_ISA << 8, NULL); + if (dev) + goto found; + return 0; +found: + pci_dev_put(dev); + return 1; +#elif defined(CONFIG_EISA) || defined(CONFIG_ISA) + return 1; +#else + return 0; +#endif +} + static __inline__ int ide_default_irq(unsigned long base) { switch (base) { @@ -45,6 +74,8 @@ static __inline__ int ide_default_irq(unsigned long base) static __inline__ unsigned long ide_default_io_base(int index) { + if (!ide_probe_legacy()) + return 0; /* * If PCI is present then it is not safe to poke around * the other legacy IDE ports. Only 0x1f0 and 0x170 are diff --git a/include/asm-powerpc/time.h b/include/asm-powerpc/time.h index fdc271ebe41..fa331dad97c 100644 --- a/include/asm-powerpc/time.h +++ b/include/asm-powerpc/time.h @@ -149,6 +149,11 @@ static inline u64 get_tb(void) } #endif /* !CONFIG_PPC64 */ +static inline u64 get_tb_or_rtc(void) +{ + return __USE_RTC() ? get_rtc() : get_tb(); +} + static inline void set_tb(unsigned int upper, unsigned int lower) { mtspr(SPRN_TBWL, 0); diff --git a/include/asm-sparc64/oplib.h b/include/asm-sparc64/oplib.h index 86dc5c018a1..55c5bb27e4d 100644 --- a/include/asm-sparc64/oplib.h +++ b/include/asm-sparc64/oplib.h @@ -297,11 +297,7 @@ extern void prom_sun4v_guest_soft_state(void); extern int prom_ihandle2path(int handle, char *buffer, int bufsize); /* Client interface level routines. */ -extern void prom_set_trap_table(unsigned long tba); -extern void prom_set_trap_table_sun4v(unsigned long tba, unsigned long mmfsa); - extern long p1275_cmd(const char *, long, ...); - #if 0 #define P1275_SIZE(x) ((((long)((x) / 32)) << 32) | (x)) diff --git a/include/asm-xtensa/bugs.h b/include/asm-xtensa/bugs.h index c4228532013..69b29d19824 100644 --- a/include/asm-xtensa/bugs.h +++ b/include/asm-xtensa/bugs.h @@ -13,10 +13,6 @@ #ifndef _XTENSA_BUGS_H #define _XTENSA_BUGS_H -#include <asm/processor.h> - -static void __init check_bugs(void) -{ -} +static void check_bugs(void) { } #endif /* _XTENSA_BUGS_H */ diff --git a/include/asm-xtensa/cache.h b/include/asm-xtensa/cache.h index 1c4a78f29ae..3bba2a540cf 100644 --- a/include/asm-xtensa/cache.h +++ b/include/asm-xtensa/cache.h @@ -19,6 +19,15 @@ #define DCACHE_WAY_SIZE (XCHAL_DCACHE_SIZE/XCHAL_DCACHE_WAYS) #define ICACHE_WAY_SIZE (XCHAL_ICACHE_SIZE/XCHAL_ICACHE_WAYS) +#define DCACHE_WAY_SHIFT (XCHAL_DCACHE_SETWIDTH + XCHAL_DCACHE_LINEWIDTH) +#define ICACHE_WAY_SHIFT (XCHAL_ICACHE_SETWIDTH + XCHAL_ICACHE_LINEWIDTH) + +/* Maximum cache size per way. */ +#if DCACHE_WAY_SIZE >= ICACHE_WAY_SIZE +# define CACHE_WAY_SIZE DCACHE_WAY_SIZE +#else +# define CACHE_WAY_SIZE ICACHE_WAY_SIZE +#endif #endif /* _XTENSA_CACHE_H */ diff --git a/include/asm-xtensa/cacheflush.h b/include/asm-xtensa/cacheflush.h index 22ef901b784..b773c57e75a 100644 --- a/include/asm-xtensa/cacheflush.h +++ b/include/asm-xtensa/cacheflush.h @@ -5,7 +5,7 @@ * License. See the file "COPYING" in the main directory of this archive * for more details. * - * (C) 2001 - 2006 Tensilica Inc. + * (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_CACHEFLUSH_H @@ -18,10 +18,7 @@ #include <asm/page.h> /* - * flush and invalidate data cache, invalidate instruction cache: - * - * __flush_invalidate_cache_all() - * __flush_invalidate_cache_range(from,sze) + * Lo-level routines for cache flushing. * * invalidate data or instruction cache: * @@ -40,26 +37,39 @@ * __flush_invalidate_dcache_all() * __flush_invalidate_dcache_page(adr) * __flush_invalidate_dcache_range(from,size) + * + * specials for cache aliasing: + * + * __flush_invalidate_dcache_page_alias(vaddr,paddr) + * __invalidate_icache_page_alias(vaddr,paddr) */ -extern void __flush_invalidate_cache_all(void); -extern void __flush_invalidate_cache_range(unsigned long, unsigned long); -extern void __flush_invalidate_dcache_all(void); +extern void __invalidate_dcache_all(void); extern void __invalidate_icache_all(void); - extern void __invalidate_dcache_page(unsigned long); extern void __invalidate_icache_page(unsigned long); extern void __invalidate_icache_range(unsigned long, unsigned long); extern void __invalidate_dcache_range(unsigned long, unsigned long); + #if XCHAL_DCACHE_IS_WRITEBACK +extern void __flush_invalidate_dcache_all(void); extern void __flush_dcache_page(unsigned long); +extern void __flush_dcache_range(unsigned long, unsigned long); extern void __flush_invalidate_dcache_page(unsigned long); extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); #else -# define __flush_dcache_page(p) do { } while(0) -# define __flush_invalidate_dcache_page(p) do { } while(0) -# define __flush_invalidate_dcache_range(p,s) do { } while(0) +# define __flush_dcache_range(p,s) do { } while(0) +# define __flush_dcache_page(p) do { } while(0) +# define __flush_invalidate_dcache_page(p) __invalidate_dcache_page(p) +# define __flush_invalidate_dcache_range(p,s) __invalidate_dcache_range(p,s) +#endif + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) +extern void __flush_invalidate_dcache_page_alias(unsigned long, unsigned long); +#endif +#if (ICACHE_WAY_SIZE > PAGE_SIZE) +extern void __invalidate_icache_page_alias(unsigned long, unsigned long); #endif /* @@ -71,17 +81,21 @@ extern void __flush_invalidate_dcache_range(unsigned long, unsigned long); * (see also Documentation/cachetlb.txt) */ -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#if (DCACHE_WAY_SIZE > PAGE_SIZE) -#define flush_cache_all() __flush_invalidate_cache_all(); -#define flush_cache_mm(mm) __flush_invalidate_cache_all(); -#define flush_cache_dup_mm(mm) __flush_invalidate_cache_all(); +#define flush_cache_all() \ + do { \ + __flush_invalidate_dcache_all(); \ + __invalidate_icache_all(); \ + } while (0) -#define flush_cache_vmap(start,end) __flush_invalidate_cache_all(); -#define flush_cache_vunmap(start,end) __flush_invalidate_cache_all(); +#define flush_cache_mm(mm) flush_cache_all() +#define flush_cache_dup_mm(mm) flush_cache_mm(mm) -extern void flush_dcache_page(struct page*); +#define flush_cache_vmap(start,end) flush_cache_all() +#define flush_cache_vunmap(start,end) flush_cache_all() +extern void flush_dcache_page(struct page*); extern void flush_cache_range(struct vm_area_struct*, ulong, ulong); extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned long); @@ -101,24 +115,39 @@ extern void flush_cache_page(struct vm_area_struct*, unsigned long, unsigned lon #endif +/* Ensure consistency between data and instruction cache. */ #define flush_icache_range(start,end) \ - __invalidate_icache_range(start,(end)-(start)) + do { \ + __flush_dcache_range(start, (end) - (start)); \ + __invalidate_icache_range(start,(end) - (start)); \ + } while (0) /* This is not required, see Documentation/cachetlb.txt */ - -#define flush_icache_page(vma,page) do { } while(0) +#define flush_icache_page(vma,page) do { } while (0) #define flush_dcache_mmap_lock(mapping) do { } while (0) #define flush_dcache_mmap_unlock(mapping) do { } while (0) +#if (DCACHE_WAY_SIZE > PAGE_SIZE) -#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ - memcpy(dst, src, len) +extern void copy_to_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); +extern void copy_from_user_page(struct vm_area_struct*, struct page*, + unsigned long, void*, const void*, unsigned long); + +#else + +#define copy_to_user_page(vma, page, vaddr, dst, src, len) \ + do { \ + memcpy(dst, src, len); \ + __flush_dcache_range((unsigned long) dst, len); \ + __invalidate_icache_range((unsigned long) dst, len); \ + } while (0) #define copy_from_user_page(vma, page, vaddr, dst, src, len) \ memcpy(dst, src, len) -#endif /* __KERNEL__ */ +#endif +#endif /* __KERNEL__ */ #endif /* _XTENSA_CACHEFLUSH_H */ - diff --git a/include/asm-xtensa/elf.h b/include/asm-xtensa/elf.h index 1569b53cec9..7083d46766a 100644 --- a/include/asm-xtensa/elf.h +++ b/include/asm-xtensa/elf.h @@ -20,6 +20,56 @@ #define EM_XTENSA 94 #define EM_XTENSA_OLD 0xABC7 +/* Xtensa relocations defined by the ABIs */ + +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_RTLD 2 +#define R_XTENSA_GLOB_DAT 3 +#define R_XTENSA_JMP_SLOT 4 +#define R_XTENSA_RELATIVE 5 +#define R_XTENSA_PLT 6 +#define R_XTENSA_OP0 8 +#define R_XTENSA_OP1 9 +#define R_XTENSA_OP2 10 +#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_ASM_SIMPLIFY 12 +#define R_XTENSA_GNU_VTINHERIT 15 +#define R_XTENSA_GNU_VTENTRY 16 +#define R_XTENSA_DIFF8 17 +#define R_XTENSA_DIFF16 18 +#define R_XTENSA_DIFF32 19 +#define R_XTENSA_SLOT0_OP 20 +#define R_XTENSA_SLOT1_OP 21 +#define R_XTENSA_SLOT2_OP 22 +#define R_XTENSA_SLOT3_OP 23 +#define R_XTENSA_SLOT4_OP 24 +#define R_XTENSA_SLOT5_OP 25 +#define R_XTENSA_SLOT6_OP 26 +#define R_XTENSA_SLOT7_OP 27 +#define R_XTENSA_SLOT8_OP 28 +#define R_XTENSA_SLOT9_OP 29 +#define R_XTENSA_SLOT10_OP 30 +#define R_XTENSA_SLOT11_OP 31 +#define R_XTENSA_SLOT12_OP 32 +#define R_XTENSA_SLOT13_OP 33 +#define R_XTENSA_SLOT14_OP 34 +#define R_XTENSA_SLOT0_ALT 35 +#define R_XTENSA_SLOT1_ALT 36 +#define R_XTENSA_SLOT2_ALT 37 +#define R_XTENSA_SLOT3_ALT 38 +#define R_XTENSA_SLOT4_ALT 39 +#define R_XTENSA_SLOT5_ALT 40 +#define R_XTENSA_SLOT6_ALT 41 +#define R_XTENSA_SLOT7_ALT 42 +#define R_XTENSA_SLOT8_ALT 43 +#define R_XTENSA_SLOT9_ALT 44 +#define R_XTENSA_SLOT10_ALT 45 +#define R_XTENSA_SLOT11_ALT 46 +#define R_XTENSA_SLOT12_ALT 47 +#define R_XTENSA_SLOT13_ALT 48 +#define R_XTENSA_SLOT14_ALT 49 + /* ELF register definitions. This is needed for core dump support. */ /* diff --git a/include/asm-xtensa/io.h b/include/asm-xtensa/io.h index 0faa614d969..47c3616ea9a 100644 --- a/include/asm-xtensa/io.h +++ b/include/asm-xtensa/io.h @@ -14,6 +14,7 @@ #ifdef __KERNEL__ #include <asm/byteorder.h> #include <asm/page.h> +#include <linux/kernel.h> #include <linux/types.h> diff --git a/include/asm-xtensa/ioctls.h b/include/asm-xtensa/ioctls.h index 39e6f23921b..0ffa942954b 100644 --- a/include/asm-xtensa/ioctls.h +++ b/include/asm-xtensa/ioctls.h @@ -91,6 +91,10 @@ #define TIOCSBRK _IO('T', 39) /* BSD compatibility */ #define TIOCCBRK _IO('T', 40) /* BSD compatibility */ #define TIOCGSID _IOR('T', 41, pid_t) /* Return the session ID of FD*/ +#define TCGETS2 _IOR('T', 42, struct termios2) +#define TCSETS2 _IOW('T', 43, struct termios2) +#define TCSETSW2 _IOW('T', 44, struct termios2) +#define TCSETSF2 _IOW('T', 45, struct termios2) #define TIOCGPTN _IOR('T',0x30, unsigned int) /* Get Pty Number (of pty-mux device) */ #define TIOCSPTLCK _IOW('T',0x31, int) /* Lock/unlock Pty */ diff --git a/include/asm-xtensa/page.h b/include/asm-xtensa/page.h index 1213cde7543..55ce2c9749a 100644 --- a/include/asm-xtensa/page.h +++ b/include/asm-xtensa/page.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/page.h + * include/asm-xtensa/page.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version2 as * published by the Free Software Foundation. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_PAGE_H @@ -14,6 +14,12 @@ #ifdef __KERNEL__ #include <asm/processor.h> +#include <asm/types.h> +#include <asm/cache.h> + +/* + * Fixed TLB translations in the processor. + */ #define XCHAL_KSEG_CACHED_VADDR 0xd0000000 #define XCHAL_KSEG_BYPASS_VADDR 0xd8000000 @@ -26,13 +32,60 @@ */ #define PAGE_SHIFT 12 -#define PAGE_SIZE (1 << PAGE_SHIFT) +#define PAGE_SIZE (__XTENSA_UL_CONST(1) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE - 1) & PAGE_MASK) #define PAGE_OFFSET XCHAL_KSEG_CACHED_VADDR -#define MAX_MEM_PFN XCHAL_KSEG_SIZE -#define PGTABLE_START 0x80000000 +#define MAX_MEM_PFN XCHAL_KSEG_SIZE +#define PGTABLE_START 0x80000000 + +/* + * Cache aliasing: + * + * If the cache size for one way is greater than the page size, we have to + * deal with cache aliasing. The cache index is wider than the page size: + * + * | |cache| cache index + * | pfn |off| virtual address + * |xxxx:X|zzz| + * | : | | + * | \ / | | + * |trans.| | + * | / \ | | + * |yyyy:Y|zzz| physical address + * + * When the page number is translated to the physical page address, the lowest + * bit(s) (X) that are part of the cache index are also translated (Y). + * If this translation changes bit(s) (X), the cache index is also afected, + * thus resulting in a different cache line than before. + * The kernel does not provide a mechanism to ensure that the page color + * (represented by this bit) remains the same when allocated or when pages + * are remapped. When user pages are mapped into kernel space, the color of + * the page might also change. + * + * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2 + * to temporarily map a patch so we can match the color. + */ + +#if DCACHE_WAY_SIZE > PAGE_SIZE +# define DCACHE_ALIAS_ORDER (DCACHE_WAY_SHIFT - PAGE_SHIFT) +# define DCACHE_ALIAS_MASK (PAGE_MASK & (DCACHE_WAY_SIZE - 1)) +# define DCACHE_ALIAS(a) (((a) & DCACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define DCACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & DCACHE_ALIAS_MASK) == 0) +#else +# define DCACHE_ALIAS_ORDER 0 +#endif + +#if ICACHE_WAY_SIZE > PAGE_SIZE +# define ICACHE_ALIAS_ORDER (ICACHE_WAY_SHIFT - PAGE_SHIFT) +# define ICACHE_ALIAS_MASK (PAGE_MASK & (ICACHE_WAY_SIZE - 1)) +# define ICACHE_ALIAS(a) (((a) & ICACHE_ALIAS_MASK) >> PAGE_SHIFT) +# define ICACHE_ALIAS_EQ(a,b) ((((a) ^ (b)) & ICACHE_ALIAS_MASK) == 0) +#else +# define ICACHE_ALIAS_ORDER 0 +#endif + #ifdef __ASSEMBLY__ @@ -58,34 +111,23 @@ typedef struct { unsigned long pgprot; } pgprot_t; /* * Pure 2^n version of get_order + * Use 'nsau' instructions if supported by the processor or the generic version. */ -static inline int get_order(unsigned long size) +#if XCHAL_HAVE_NSA + +static inline __attribute_const__ int get_order(unsigned long size) { - int order; -#ifndef XCHAL_HAVE_NSU - unsigned long x1, x2, x4, x8, x16; - - size = (size + PAGE_SIZE - 1) >> PAGE_SHIFT; - x1 = size & 0xAAAAAAAA; - x2 = size & 0xCCCCCCCC; - x4 = size & 0xF0F0F0F0; - x8 = size & 0xFF00FF00; - x16 = size & 0xFFFF0000; - order = x2 ? 2 : 0; - order += (x16 != 0) * 16; - order += (x8 != 0) * 8; - order += (x4 != 0) * 4; - order += (x1 != 0); - - return order; -#else - size = (size - 1) >> PAGE_SHIFT; - asm ("nsau %0, %1" : "=r" (order) : "r" (size)); - return 32 - order; -#endif + int lz; + asm ("nsau %0, %1" : "=r" (lz) : "r" ((size - 1) >> PAGE_SHIFT)); + return 32 - lz; } +#else + +# include <asm-generic/page.h> + +#endif struct page; extern void clear_page(void *page); @@ -96,11 +138,11 @@ extern void copy_page(void *to, void *from); * some extra work */ -#if (DCACHE_WAY_SIZE > PAGE_SIZE) -void clear_user_page(void *addr, unsigned long vaddr, struct page* page); -void copy_user_page(void *to,void* from,unsigned long vaddr,struct page* page); +#if DCACHE_WAY_SIZE > PAGE_SIZE +extern void clear_user_page(void*, unsigned long, struct page*); +extern void copy_user_page(void*, void*, unsigned long, struct page*); #else -# define clear_user_page(page,vaddr,pg) clear_page(page) +# define clear_user_page(page, vaddr, pg) clear_page(page) # define copy_user_page(to, from, vaddr, pg) copy_page(to, from) #endif diff --git a/include/asm-xtensa/pgalloc.h b/include/asm-xtensa/pgalloc.h index d56ddf2055e..3e5b5652510 100644 --- a/include/asm-xtensa/pgalloc.h +++ b/include/asm-xtensa/pgalloc.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/pgalloc.h + * include/asm-xtensa/pgalloc.h * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Copyright (C) 2001-2005 Tensilica Inc. + * Copyright (C) 2001-2007 Tensilica Inc. */ #ifndef _XTENSA_PGALLOC_H @@ -13,103 +13,54 @@ #ifdef __KERNEL__ -#include <linux/threads.h> #include <linux/highmem.h> -#include <asm/processor.h> -#include <asm/cacheflush.h> - - -/* Cache aliasing: - * - * If the cache size for one way is greater than the page size, we have to - * deal with cache aliasing. The cache index is wider than the page size: - * - * |cache | - * |pgnum |page| virtual address - * |xxxxxX|zzzz| - * | | | - * \ / | | - * trans.| | - * / \ | | - * |yyyyyY|zzzz| physical address - * - * When the page number is translated to the physical page address, the lowest - * bit(s) (X) that are also part of the cache index are also translated (Y). - * If this translation changes this bit (X), the cache index is also afected, - * thus resulting in a different cache line than before. - * The kernel does not provide a mechanism to ensure that the page color - * (represented by this bit) remains the same when allocated or when pages - * are remapped. When user pages are mapped into kernel space, the color of - * the page might also change. - * - * We use the address space VMALLOC_END ... VMALLOC_END + DCACHE_WAY_SIZE * 2 - * to temporarily map a patch so we can match the color. - */ - -#if (DCACHE_WAY_SIZE > PAGE_SIZE) -# define PAGE_COLOR_MASK (PAGE_MASK & (DCACHE_WAY_SIZE-1)) -# define PAGE_COLOR(a) \ - (((unsigned long)(a)&PAGE_COLOR_MASK) >> PAGE_SHIFT) -# define PAGE_COLOR_EQ(a,b) \ - ((((unsigned long)(a) ^ (unsigned long)(b)) & PAGE_COLOR_MASK) == 0) -# define PAGE_COLOR_MAP0(v) \ - (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK)) -# define PAGE_COLOR_MAP1(v) \ - (VMALLOC_END + ((unsigned long)(v) & PAGE_COLOR_MASK) + DCACHE_WAY_SIZE) -#endif /* * Allocating and freeing a pmd is trivial: the 1-entry pmd is * inside the pgd, so has no extra memory associated with it. */ -#define pgd_free(pgd) free_page((unsigned long)(pgd)) - -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK +#define pmd_populate_kernel(mm, pmdp, ptep) \ + (pmd_val(*(pmdp)) = ((unsigned long)ptep)) +#define pmd_populate(mm, pmdp, page) \ + (pmd_val(*(pmdp)) = ((unsigned long)page_to_virt(page))) -static inline void -pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmdp, pte_t *pte) +static inline pgd_t* +pgd_alloc(struct mm_struct *mm) { - pmd_val(*(pmdp)) = (unsigned long)(pte); - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); + return (pgd_t*) __get_free_pages(GFP_KERNEL | __GFP_ZERO, PGD_ORDER); } -static inline void -pmd_populate(struct mm_struct *mm, pmd_t *pmdp, struct page *page) +static inline void pgd_free(pgd_t *pgd) { - pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page); - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); + free_page((unsigned long)pgd); } +/* Use a slab cache for the pte pages (see also sparc64 implementation) */ +extern struct kmem_cache *pgtable_cache; -#else - -# define pmd_populate_kernel(mm, pmdp, pte) \ - (pmd_val(*(pmdp)) = (unsigned long)(pte)) -# define pmd_populate(mm, pmdp, page) \ - (pmd_val(*(pmdp)) = (unsigned long)page_to_virt(page)) - -#endif - -static inline pgd_t* -pgd_alloc(struct mm_struct *mm) +static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm, + unsigned long address) { - pgd_t *pgd; - - pgd = (pgd_t *)__get_free_pages(GFP_KERNEL|__GFP_ZERO, PGD_ORDER); - - if (likely(pgd != NULL)) - __flush_dcache_page((unsigned long)pgd); + return kmem_cache_alloc(pgtable_cache, GFP_KERNEL|__GFP_REPEAT); +} - return pgd; +static inline struct page *pte_alloc_one(struct mm_struct *mm, + unsigned long addr) +{ + return virt_to_page(pte_alloc_one_kernel(mm, addr)); } -extern pte_t* pte_alloc_one_kernel(struct mm_struct* mm, unsigned long addr); -extern struct page* pte_alloc_one(struct mm_struct* mm, unsigned long addr); +static inline void pte_free_kernel(pte_t *pte) +{ + kmem_cache_free(pgtable_cache, pte); +} -#define pte_free_kernel(pte) free_page((unsigned long)pte) -#define pte_free(pte) __free_page(pte) +static inline void pte_free(struct page *page) +{ + kmem_cache_free(pgtable_cache, page_address(page)); +} #endif /* __KERNEL__ */ #endif /* _XTENSA_PGALLOC_H */ diff --git a/include/asm-xtensa/pgtable.h b/include/asm-xtensa/pgtable.h index 06850f3b26a..c0fcc1c9660 100644 --- a/include/asm-xtensa/pgtable.h +++ b/include/asm-xtensa/pgtable.h @@ -1,11 +1,11 @@ /* - * linux/include/asm-xtensa/pgtable.h + * include/asm-xtensa/pgtable.h * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version2 as + * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. * - * Copyright (C) 2001 - 2005 Tensilica Inc. + * Copyright (C) 2001 - 2007 Tensilica Inc. */ #ifndef _XTENSA_PGTABLE_H @@ -23,7 +23,7 @@ /* * The Xtensa architecture port of Linux has a two-level page table system, - * i.e. the logical three-level Linux page table layout are folded. + * i.e. the logical three-level Linux page table layout is folded. * Each task has the following memory page tables: * * PGD table (page directory), ie. 3rd-level page table: @@ -43,6 +43,7 @@ * * The individual pages are 4 kB big with special pages for the empty_zero_page. */ + #define PGDIR_SHIFT 22 #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE-1)) @@ -53,24 +54,26 @@ */ #define PTRS_PER_PTE 1024 #define PTRS_PER_PTE_SHIFT 10 -#define PTRS_PER_PMD 1 #define PTRS_PER_PGD 1024 #define PGD_ORDER 0 -#define PMD_ORDER 0 #define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) -#define FIRST_USER_ADDRESS 0 +#define FIRST_USER_ADDRESS 0 #define FIRST_USER_PGD_NR (FIRST_USER_ADDRESS >> PGDIR_SHIFT) -/* virtual memory area. We keep a distance to other memory regions to be +/* + * Virtual memory area. We keep a distance to other memory regions to be * on the safe side. We also use this area for cache aliasing. */ -// FIXME: virtual memory area must be configuration-dependent - #define VMALLOC_START 0xC0000000 -#define VMALLOC_END 0xC7FF0000 +#define VMALLOC_END 0xC6FEFFFF +#define TLBTEMP_BASE_1 0xC6FF0000 +#define TLBTEMP_BASE_2 0xC6FF8000 +#define MODULE_START 0xC7000000 +#define MODULE_END 0xC7FFFFFF -/* Xtensa Linux config PTE layout (when present): +/* + * Xtensa Linux config PTE layout (when present): * 31-12: PPN * 11-6: Software * 5-4: RING @@ -86,47 +89,55 @@ * See further below for PTE layout for swapped-out pages. */ -#define _PAGE_VALID (1<<0) /* hardware: page is accessible */ -#define _PAGE_WRENABLE (1<<1) /* hardware: page is writable */ +#define _PAGE_HW_EXEC (1<<0) /* hardware: page is executable */ +#define _PAGE_HW_WRITE (1<<1) /* hardware: page is writable */ + +#define _PAGE_FILE (1<<1) /* non-linear mapping, if !present */ +#define _PAGE_PROTNONE (3<<0) /* special case for VM_PROT_NONE */ /* None of these cache modes include MP coherency: */ -#define _PAGE_NO_CACHE (0<<2) /* bypass, non-speculative */ -#if XCHAL_DCACHE_IS_WRITEBACK -# define _PAGE_WRITEBACK (1<<2) /* write back */ -# define _PAGE_WRITETHRU (2<<2) /* write through */ -#else -# define _PAGE_WRITEBACK (1<<2) /* assume write through */ -# define _PAGE_WRITETHRU (1<<2) -#endif -#define _PAGE_NOALLOC (3<<2) /* don't allocate cache,if not cached */ -#define _CACHE_MASK (3<<2) +#define _PAGE_CA_BYPASS (0<<2) /* bypass, non-speculative */ +#define _PAGE_CA_WB (1<<2) /* write-back */ +#define _PAGE_CA_WT (2<<2) /* write-through */ +#define _PAGE_CA_MASK (3<<2) +#define _PAGE_INVALID (3<<2) #define _PAGE_USER (1<<4) /* user access (ring=1) */ -#define _PAGE_KERNEL (0<<4) /* kernel access (ring=0) */ /* Software */ -#define _PAGE_RW (1<<6) /* software: page writable */ +#define _PAGE_WRITABLE_BIT 6 +#define _PAGE_WRITABLE (1<<6) /* software: page writable */ #define _PAGE_DIRTY (1<<7) /* software: page dirty */ #define _PAGE_ACCESSED (1<<8) /* software: page accessed (read) */ -#define _PAGE_FILE (1<<9) /* nonlinear file mapping*/ -#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _CACHE_MASK | _PAGE_DIRTY) -#define _PAGE_PRESENT ( _PAGE_VALID | _PAGE_WRITEBACK | _PAGE_ACCESSED) +/* On older HW revisions, we always have to set bit 0 */ +#if XCHAL_HW_VERSION_MAJOR < 2000 +# define _PAGE_VALID (1<<0) +#else +# define _PAGE_VALID 0 +#endif -#ifdef CONFIG_MMU +#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) +#define _PAGE_PRESENT (_PAGE_VALID | _PAGE_CA_WB | _PAGE_ACCESSED) -# define PAGE_NONE __pgprot(_PAGE_PRESENT) -# define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_RW) -# define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER) -# define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER) -# define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_KERNEL | _PAGE_WRENABLE) -# define PAGE_INVALID __pgprot(_PAGE_USER) +#ifdef CONFIG_MMU -# if (DCACHE_WAY_SIZE > PAGE_SIZE) -# define PAGE_DIRECTORY __pgprot(_PAGE_VALID | _PAGE_ACCESSED | _PAGE_KERNEL) -# else -# define PAGE_DIRECTORY __pgprot(_PAGE_PRESENT | _PAGE_KERNEL) -# endif +#define PAGE_NONE __pgprot(_PAGE_INVALID | _PAGE_USER | _PAGE_PROTNONE) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER) +#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_HW_EXEC) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE) +#define PAGE_SHARED_EXEC \ + __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_WRITABLE | _PAGE_HW_EXEC) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_HW_WRITE) +#define PAGE_KERNEL_EXEC __pgprot(_PAGE_PRESENT|_PAGE_HW_WRITE|_PAGE_HW_EXEC) + +#if (DCACHE_WAY_SIZE > PAGE_SIZE) +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED) +#else +# define _PAGE_DIRECTORY (_PAGE_VALID | _PAGE_ACCESSED | _PAGE_CA_WB) +#endif #else /* no mmu */ @@ -145,23 +156,23 @@ * What follows is the closest we can get by reasonable means.. * See linux/mm/mmap.c for protection_map[] array that uses these definitions. */ -#define __P000 PAGE_NONE /* private --- */ -#define __P001 PAGE_READONLY /* private --r */ -#define __P010 PAGE_COPY /* private -w- */ -#define __P011 PAGE_COPY /* private -wr */ -#define __P100 PAGE_READONLY /* private x-- */ -#define __P101 PAGE_READONLY /* private x-r */ -#define __P110 PAGE_COPY /* private xw- */ -#define __P111 PAGE_COPY /* private xwr */ - -#define __S000 PAGE_NONE /* shared --- */ -#define __S001 PAGE_READONLY /* shared --r */ -#define __S010 PAGE_SHARED /* shared -w- */ -#define __S011 PAGE_SHARED /* shared -wr */ -#define __S100 PAGE_READONLY /* shared x-- */ -#define __S101 PAGE_READONLY /* shared x-r */ -#define __S110 PAGE_SHARED /* shared xw- */ -#define __S111 PAGE_SHARED /* shared xwr */ +#define __P000 PAGE_NONE /* private --- */ +#define __P001 PAGE_READONLY /* private --r */ +#define __P010 PAGE_COPY /* private -w- */ +#define __P011 PAGE_COPY /* private -wr */ +#define __P100 PAGE_READONLY_EXEC /* private x-- */ +#define __P101 PAGE_READONLY_EXEC /* private x-r */ +#define __P110 PAGE_COPY_EXEC /* private xw- */ +#define __P111 PAGE_COPY_EXEC /* private xwr */ + +#define __S000 PAGE_NONE /* shared --- */ +#define __S001 PAGE_READONLY /* shared --r */ +#define __S010 PAGE_SHARED /* shared -w- */ +#define __S011 PAGE_SHARED /* shared -wr */ +#define __S100 PAGE_READONLY_EXEC /* shared x-- */ +#define __S101 PAGE_READONLY_EXEC /* shared x-r */ +#define __S110 PAGE_SHARED_EXEC /* shared xw- */ +#define __S111 PAGE_SHARED_EXEC /* shared xwr */ #ifndef __ASSEMBLY__ @@ -183,35 +194,42 @@ extern pgd_t swapper_pg_dir[PAGE_SIZE/sizeof(pgd_t)]; #define pmd_page(pmd) virt_to_page(pmd_val(pmd)) /* - * The following only work if pte_present() is true. + * pte status. */ -#define pte_none(pte) (!(pte_val(pte) ^ _PAGE_USER)) -#define pte_present(pte) (pte_val(pte) & _PAGE_VALID) +#define pte_none(pte) (pte_val(pte) == _PAGE_INVALID) +#define pte_present(pte) \ + (((pte_val(pte) & _PAGE_CA_MASK) != _PAGE_INVALID) \ + || ((pte_val(pte) & _PAGE_PROTNONE) == _PAGE_PROTNONE)) #define pte_clear(mm,addr,ptep) \ - do { update_pte(ptep, __pte(_PAGE_USER)); } while(0) + do { update_pte(ptep, __pte(_PAGE_INVALID)); } while(0) #define pmd_none(pmd) (!pmd_val(pmd)) #define pmd_present(pmd) (pmd_val(pmd) & PAGE_MASK) -#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0) #define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK) +#define pmd_clear(pmdp) do { set_pmd(pmdp, __pmd(0)); } while (0) -/* Note: We use the _PAGE_USER bit to indicate write-protect kernel memory */ - -static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_RW; } +static inline int pte_write(pte_t pte) { return pte_val(pte) & _PAGE_WRITABLE; } static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } static inline int pte_file(pte_t pte) { return pte_val(pte) & _PAGE_FILE; } -static inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) &= ~(_PAGE_RW | _PAGE_WRENABLE); return pte; } -static inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } -static inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } -static inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } -static inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } -static inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) |= _PAGE_RW; return pte; } +static inline pte_t pte_wrprotect(pte_t pte) + { pte_val(pte) &= ~(_PAGE_WRITABLE | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkclean(pte_t pte) + { pte_val(pte) &= ~(_PAGE_DIRTY | _PAGE_HW_WRITE); return pte; } +static inline pte_t pte_mkold(pte_t pte) + { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkdirty(pte_t pte) + { pte_val(pte) |= _PAGE_DIRTY; return pte; } +static inline pte_t pte_mkyoung(pte_t pte) + { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +static inline pte_t pte_mkwrite(pte_t pte) + { pte_val(pte) |= _PAGE_WRITABLE; return pte; } /* * Conversion functions: convert a page and protection to a page entry, * and a page entry and page directory to the page they refer to. */ + #define pte_pfn(pte) (pte_val(pte) >> PAGE_SHIFT) #define pte_same(a,b) (pte_val(a) == pte_val(b)) #define pte_page(x) pfn_to_page(pte_pfn(x)) @@ -232,8 +250,9 @@ static inline void update_pte(pte_t *ptep, pte_t pteval) { *ptep = pteval; #if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (ptep)); + __asm__ __volatile__ ("dhwb %0, 0" :: "a" (ptep)); #endif + } struct mm_struct; @@ -249,9 +268,6 @@ static inline void set_pmd(pmd_t *pmdp, pmd_t pmdval) { *pmdp = pmdval; -#if (DCACHE_WAY_SIZE > PAGE_SIZE) && XCHAL_DCACHE_IS_WRITEBACK - __asm__ __volatile__ ("memw; dhwb %0, 0; dsync" :: "a" (pmdp)); -#endif } struct vm_area_struct; @@ -306,52 +322,34 @@ ptep_set_wrprotect(struct mm_struct *mm, unsigned long addr, pte_t *ptep) /* * Encode and decode a swap entry. - * Each PTE in a process VM's page table is either: - * "present" -- valid and not swapped out, protection bits are meaningful; - * "not present" -- which further subdivides in these two cases: - * "none" -- no mapping at all; identified by pte_none(), set by pte_clear( - * "swapped out" -- the page is swapped out, and the SWP macros below - * are used to store swap file info in the PTE itself. * - * In the Xtensa processor MMU, any PTE entries in user space (or anywhere - * in virtual memory that can map differently across address spaces) - * must have a correct ring value that represents the RASID field that - * is changed when switching address spaces. Eg. such PTE entries cannot - * be set to ring zero, because that can cause a (global) kernel ASID - * entry to be created in the TLBs (even with invalid cache attribute), - * potentially causing a multihit exception when going back to another - * address space that mapped the same virtual address at another ring. - * - * SO: we avoid using ring bits (_PAGE_RING_MASK) in "not present" PTEs. - * We also avoid using the _PAGE_VALID bit which must be zero for non-present - * pages. - * - * We end up with the following available bits: 1..3 and 7..31. - * We don't bother with 1..3 for now (we can use them later if needed), - * and chose to allocate 6 bits for SWP_TYPE and the remaining 19 bits - * for SWP_OFFSET. At least 5 bits are needed for SWP_TYPE, because it - * is currently implemented as an index into swap_info[MAX_SWAPFILES] - * and MAX_SWAPFILES is currently defined as 32 in <linux/swap.h>. - * However, for some reason all other architectures in the 2.4 kernel - * reserve either 6, 7, or 8 bits so I'll not detract from that for now. :) - * SWP_OFFSET is an offset into the swap file in page-size units, so - * with 4 kB pages, 19 bits supports a maximum swap file size of 2 GB. - * - * FIXME: 2 GB isn't very big. Other bits can be used to allow - * larger swap sizes. In the meantime, it appears relatively easy to get - * around the 2 GB limitation by simply using multiple swap files. + * Format of swap pte: + * bit 0 MBZ + * bit 1 page-file (must be zero) + * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID) + * bits 4 - 5 ring protection (must be 01: _PAGE_USER) + * bits 6 - 10 swap type (5 bits -> 32 types) + * bits 11 - 31 swap offset / PAGE_SIZE (21 bits -> 8GB) + + * Format of file pte: + * bit 0 MBZ + * bit 1 page-file (must be one: _PAGE_FILE) + * bits 2 - 3 page hw access mode (must be 11: _PAGE_INVALID) + * bits 4 - 5 ring protection (must be 01: _PAGE_USER) + * bits 6 - 31 file offset / PAGE_SIZE */ -#define __swp_type(entry) (((entry).val >> 7) & 0x3f) -#define __swp_offset(entry) ((entry).val >> 13) -#define __swp_entry(type,offs) ((swp_entry_t) {((type) << 7) | ((offs) << 13)}) +#define __swp_type(entry) (((entry).val >> 6) & 0x1f) +#define __swp_offset(entry) ((entry).val >> 11) +#define __swp_entry(type,offs) \ + ((swp_entry_t) {((type) << 6) | ((offs) << 11) | _PAGE_INVALID}) #define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) #define __swp_entry_to_pte(x) ((pte_t) { (x).val }) -#define PTE_FILE_MAX_BITS 29 -#define pte_to_pgoff(pte) (pte_val(pte) >> 3) -#define pgoff_to_pte(off) ((pte_t) { ((off) << 3) | _PAGE_FILE }) - +#define PTE_FILE_MAX_BITS 28 +#define pte_to_pgoff(pte) (pte_val(pte) >> 4) +#define pgoff_to_pte(off) \ + ((pte_t) { ((off) << 4) | _PAGE_INVALID | _PAGE_FILE }) #endif /* !defined (__ASSEMBLY__) */ @@ -394,13 +392,12 @@ extern void update_mmu_cache(struct vm_area_struct * vma, * remap a physical page `pfn' of size `size' with page protection `prot' * into virtual address `from' */ + #define io_remap_pfn_range(vma,from,pfn,size,prot) \ remap_pfn_range(vma, from, pfn, size, prot) -/* No page table caches to init */ - -#define pgtable_cache_init() do { } while (0) +extern void pgtable_cache_init(void); typedef pte_t *pte_addr_t; diff --git a/include/asm-xtensa/processor.h b/include/asm-xtensa/processor.h index 4feb9f7f35a..35145bcd96e 100644 --- a/include/asm-xtensa/processor.h +++ b/include/asm-xtensa/processor.h @@ -33,7 +33,7 @@ * the 1 GB requirement applies to the stack as well. */ -#define TASK_SIZE 0x40000000 +#define TASK_SIZE __XTENSA_UL_CONST(0x40000000) /* * General exception cause assigned to debug exceptions. Debug exceptions go diff --git a/include/asm-xtensa/syscall.h b/include/asm-xtensa/syscall.h index 6cb0d42f11c..05cebf8f62b 100644 --- a/include/asm-xtensa/syscall.h +++ b/include/asm-xtensa/syscall.h @@ -1,3 +1,13 @@ +/* + * include/asm-xtensa/syscall.h + * + * This file is subject to the terms and conditions of the GNU General Public + * License. See the file "COPYING" in the main directory of this archive + * for more details. + * + * Copyright (C) 2001 - 2007 Tensilica Inc. + */ + struct pt_regs; struct sigaction; asmlinkage long xtensa_execve(char*, char**, char**, struct pt_regs*); @@ -17,4 +27,16 @@ asmlinkage long sys_rt_sigaction(int, const struct sigaction __user *, struct sigaction __user *, size_t); -asmlinkage long xtensa_shmat(int shmid, char __user *shmaddr, int shmflg); +asmlinkage long xtensa_shmat(int, char __user *, int); +asmlinkage long xtensa_fadvise64_64(int, int, + unsigned long long, unsigned long long); + +/* Should probably move to linux/syscalls.h */ +struct pollfd; +asmlinkage long sys_pselect6(int n, fd_set __user *inp, fd_set __user *outp, + fd_set __user *exp, struct timespec __user *tsp, void __user *sig); +asmlinkage long sys_ppoll(struct pollfd __user *ufds, unsigned int nfds, + struct timespec __user *tsp, const sigset_t __user *sigmask, + size_t sigsetsize); + + diff --git a/include/asm-xtensa/termbits.h b/include/asm-xtensa/termbits.h index 9972c25ec86..85aa6a3c0b6 100644 --- a/include/asm-xtensa/termbits.h +++ b/include/asm-xtensa/termbits.h @@ -157,6 +157,7 @@ struct ktermios { #define HUPCL 0002000 #define CLOCAL 0004000 #define CBAUDEX 0010000 +#define BOTHER 0010000 #define B57600 0010001 #define B115200 0010002 #define B230400 0010003 @@ -172,10 +173,12 @@ struct ktermios { #define B3000000 0010015 #define B3500000 0010016 #define B4000000 0010017 -#define CIBAUD 002003600000 /* input baud rate (not used) */ +#define CIBAUD 002003600000 /* input baud rate */ #define CMSPAR 010000000000 /* mark or space (stick) parity */ #define CRTSCTS 020000000000 /* flow control */ +#define IBSHIFT 16 /* Shift from CBAUD to CIBAUD */ + /* c_lflag bits */ #define ISIG 0000001 diff --git a/include/asm-xtensa/termios.h b/include/asm-xtensa/termios.h index f14b42c8dac..4673f42f88a 100644 --- a/include/asm-xtensa/termios.h +++ b/include/asm-xtensa/termios.h @@ -95,8 +95,10 @@ struct termio { copy_to_user((termio)->c_cc, (termios)->c_cc, NCC); \ }) -#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios)) -#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios)) +#define user_termios_to_kernel_termios(k, u) copy_from_user(k, u, sizeof(struct termios2)) +#define kernel_termios_to_user_termios(u, k) copy_to_user(u, k, sizeof(struct termios2)) +#define user_termios_to_kernel_termios_1(k, u) copy_from_user(k, u, sizeof(struct termios)) +#define kernel_termios_to_user_termios_1(u, k) copy_to_user(u, k, sizeof(struct termios)) #endif /* __KERNEL__ */ diff --git a/include/asm-xtensa/timex.h b/include/asm-xtensa/timex.h index 28c7985a400..a5fca59fba9 100644 --- a/include/asm-xtensa/timex.h +++ b/include/asm-xtensa/timex.h @@ -41,10 +41,10 @@ extern unsigned long ccount_per_jiffy; extern unsigned long ccount_nsec; #define CCOUNT_PER_JIFFY ccount_per_jiffy -#define CCOUNT_NSEC ccount_nsec +#define NSEC_PER_CCOUNT ccount_nsec #else #define CCOUNT_PER_JIFFY (CONFIG_XTENSA_CPU_CLOCK*(1000000UL/HZ)) -#define CCOUNT_NSEC (1000000000UL / CONFIG_XTENSA_CPU_CLOCK) +#define NSEC_PER_CCOUNT (1000UL / CONFIG_XTENSA_CPU_CLOCK) #endif diff --git a/include/asm-xtensa/tlb.h b/include/asm-xtensa/tlb.h index 4562b2dcfbc..4830232017a 100644 --- a/include/asm-xtensa/tlb.h +++ b/include/asm-xtensa/tlb.h @@ -11,14 +11,36 @@ #ifndef _XTENSA_TLB_H #define _XTENSA_TLB_H -#define tlb_start_vma(tlb,vma) do { } while (0) -#define tlb_end_vma(tlb,vma) do { } while (0) -#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0) +#include <asm/cache.h> +#include <asm/page.h> + +#if (DCACHE_WAY_SIZE <= PAGE_SIZE) + +/* Note, read http://lkml.org/lkml/2004/1/15/6 */ + +# define tlb_start_vma(tlb,vma) do { } while (0) +# define tlb_end_vma(tlb,vma) do { } while (0) + +#else +# define tlb_start_vma(tlb, vma) \ + do { \ + if (!tlb->fullmm) \ + flush_cache_range(vma, vma->vm_start, vma->vm_end); \ + } while(0) + +# define tlb_end_vma(tlb, vma) \ + do { \ + if (!tlb->fullmm) \ + flush_tlb_range(vma, vma->vm_start, vma->vm_end); \ + } while(0) + +#endif + +#define __tlb_remove_tlb_entry(tlb,pte,addr) do { } while (0) #define tlb_flush(tlb) flush_tlb_mm((tlb)->mm) #include <asm-generic/tlb.h> -#include <asm/page.h> #define __pte_free_tlb(tlb,pte) pte_free(pte) diff --git a/include/asm-xtensa/types.h b/include/asm-xtensa/types.h index 9d99a8e9e33..f1e84526f99 100644 --- a/include/asm-xtensa/types.h +++ b/include/asm-xtensa/types.h @@ -11,6 +11,15 @@ #ifndef _XTENSA_TYPES_H #define _XTENSA_TYPES_H + +#ifdef __ASSEMBLY__ +# define __XTENSA_UL(x) (x) +# define __XTENSA_UL_CONST(x) x +#else +# define __XTENSA_UL(x) ((unsigned long)(x)) +# define __XTENSA_UL_CONST(x) x##UL +#endif + #ifndef __ASSEMBLY__ typedef unsigned short umode_t; diff --git a/include/asm-xtensa/unistd.h b/include/asm-xtensa/unistd.h index 9bd34024431..92968aabe34 100644 --- a/include/asm-xtensa/unistd.h +++ b/include/asm-xtensa/unistd.h @@ -151,7 +151,7 @@ __SYSCALL( 61, sys_fcntl64, 3) #define __NR_available62 62 __SYSCALL( 62, sys_ni_syscall, 0) #define __NR_fadvise64_64 63 -__SYSCALL( 63, sys_fadvise64_64, 6) +__SYSCALL( 63, xtensa_fadvise64_64, 6) #define __NR_utime 64 /* glibc 2.3.3 ?? */ __SYSCALL( 64, sys_utime, 2) #define __NR_utimes 65 @@ -339,8 +339,8 @@ __SYSCALL(148, sys_setpgid, 2) __SYSCALL(149, sys_getpgid, 1) #define __NR_getppid 150 __SYSCALL(150, sys_getppid, 0) -#define __NR_available151 151 -__SYSCALL(151, sys_ni_syscall, 0) +#define __NR_getpgrp 151 +__SYSCALL(151, sys_getpgrp, 0) #define __NR_reserved152 152 /* set_thread_area */ __SYSCALL(152, sys_ni_syscall, 0) @@ -577,7 +577,112 @@ __SYSCALL(258, sys_keyctl, 5) #define __NR_available259 259 __SYSCALL(259, sys_ni_syscall, 0) -#define __NR_syscall_count 261 + +#define __NR_readahead 260 +__SYSCALL(260, sys_readahead, 5) +#define __NR_remap_file_pages 261 +__SYSCALL(261, sys_remap_file_pages, 5) +#define __NR_migrate_pages 262 +__SYSCALL(262, sys_migrate_pages, 0) +#define __NR_mbind 263 +__SYSCALL(263, sys_mbind, 6) +#define __NR_get_mempolicy 264 +__SYSCALL(264, sys_get_mempolicy, 5) +#define __NR_set_mempolicy 265 +__SYSCALL(265, sys_set_mempolicy, 3) +#define __NR_unshare 266 +__SYSCALL(266, sys_unshare, 1) +#define __NR_move_pages 267 +__SYSCALL(267, sys_move_pages, 0) +#define __NR_splice 268 +__SYSCALL(268, sys_splice, 0) +#define __NR_tee 269 +__SYSCALL(269, sys_tee, 0) +#define __NR_vmsplice 270 +__SYSCALL(270, sys_vmsplice, 0) +#define __NR_available271 271 +__SYSCALL(271, sys_ni_syscall, 0) + +#define __NR_pselect6 272 +__SYSCALL(272, sys_pselect6, 0) +#define __NR_ppoll 273 +__SYSCALL(273, sys_ppoll, 0) +#define __NR_epoll_pwait 274 +__SYSCALL(274, sys_epoll_pwait, 0) +#define __NR_available275 275 +__SYSCALL(275, sys_ni_syscall, 0) + +#define __NR_inotify_init 276 +__SYSCALL(276, sys_inotify_init, 0) +#define __NR_inotify_add_watch 277 +__SYSCALL(277, sys_inotify_add_watch, 3) +#define __NR_inotify_rm_watch 278 +__SYSCALL(278, sys_inotify_rm_watch, 2) +#define __NR_available279 279 +__SYSCALL(279, sys_ni_syscall, 0) + +#define __NR_getcpu 280 +__SYSCALL(280, sys_getcpu, 0) +#define __NR_kexec_load 281 +__SYSCALL(281, sys_ni_syscall, 0) + +#define __NR_ioprio_set 282 +__SYSCALL(282, sys_ioprio_set, 2) +#define __NR_ioprio_get 283 +__SYSCALL(283, sys_ioprio_get, 3) + +#define __NR_set_robust_list 284 +__SYSCALL(284, sys_set_robust_list, 3) +#define __NR_get_robust_list 285 +__SYSCALL(285, sys_get_robust_list, 3) +#define __NR_reserved286 286 /* sync_file_rangeX */ +__SYSCALL(286, sys_ni_syscall, 3) +#define __NR_available287 287 +__SYSCALL(287, sys_faccessat, 0) + +/* Relative File Operations */ + +#define __NR_openat 288 +__SYSCALL(288, sys_openat, 4) +#define __NR_mkdirat 289 +__SYSCALL(289, sys_mkdirat, 3) +#define __NR_mknodat 290 +__SYSCALL(290, sys_mknodat, 4) +#define __NR_unlinkat 291 +__SYSCALL(291, sys_unlinkat, 3) +#define __NR_renameat 292 +__SYSCALL(292, sys_renameat, 4) +#define __NR_linkat 293 +__SYSCALL(293, sys_linkat, 5) +#define __NR_symlinkat 294 +__SYSCALL(294, sys_symlinkat, 3) +#define __NR_readlinkat 295 +__SYSCALL(295, sys_readlinkat, 4) +#define __NR_utimensat 296 +__SYSCALL(296, sys_utimensat, 0) +#define __NR_fchownat 297 +__SYSCALL(297, sys_fchownat, 5) +#define __NR_futimesat 298 +__SYSCALL(298, sys_futimesat, 4) +#define __NR_fstatat64 299 +__SYSCALL(299, sys_fstatat64, 0) +#define __NR_fchmodat 300 +__SYSCALL(300, sys_fchmodat, 4) +#define __NR_faccessat 301 +__SYSCALL(301, sys_faccessat, 4) +#define __NR_available302 302 +__SYSCALL(302, sys_ni_syscall, 0) +#define __NR_available303 303 +__SYSCALL(303, sys_ni_syscall, 0) + +#define __NR_signalfd 304 +__SYSCALL(304, sys_signalfd, 3) +#define __NR_timerfd 305 +__SYSCALL(305, sys_timerfd, 4) +#define __NR_eventfd 306 +__SYSCALL(306, sys_eventfd, 1) + +#define __NR_syscall_count 307 /* * sysxtensa syscall handler @@ -612,8 +717,19 @@ __SYSCALL(259, sys_ni_syscall, 0) #define __ARCH_WANT_SYS_LLSEEK #define __ARCH_WANT_SYS_RT_SIGACTION #define __ARCH_WANT_SYS_RT_SIGSUSPEND +#define __ARCH_WANT_SYS_GETPGRP -#endif /* __KERNEL__ */ +/* + * Ignore legacy system calls in the checksyscalls.sh script + */ -#endif /* _XTENSA_UNISTD_H */ +#define __IGNORE_fork /* use clone */ +#define __IGNORE_time +#define __IGNORE_alarm /* use setitimer */ +#define __IGNORE_pause +#define __IGNORE_mmap /* use mmap2 */ +#define __IGNORE_vfork /* use clone */ +#define __IGNORE_fadvise64 /* use fadvise64_64 */ +#endif /* __KERNEL__ */ +#endif /* _XTENSA_UNISTD_H */ diff --git a/include/linux/isa.h b/include/linux/isa.h index 1b855335cb1..b0270e3814c 100644 --- a/include/linux/isa.h +++ b/include/linux/isa.h @@ -22,7 +22,18 @@ struct isa_driver { #define to_isa_driver(x) container_of((x), struct isa_driver, driver) +#ifdef CONFIG_ISA int isa_register_driver(struct isa_driver *, unsigned int); void isa_unregister_driver(struct isa_driver *); +#else +static inline int isa_register_driver(struct isa_driver *d, unsigned int i) +{ + return 0; +} + +static inline void isa_unregister_driver(struct isa_driver *d) +{ +} +#endif #endif /* __LINUX_ISA_H */ diff --git a/include/linux/mempolicy.h b/include/linux/mempolicy.h index 5bdd656e88c..a020eb2d4e2 100644 --- a/include/linux/mempolicy.h +++ b/include/linux/mempolicy.h @@ -159,7 +159,7 @@ extern void mpol_fix_fork_child_flag(struct task_struct *p); extern struct mempolicy default_policy; extern struct zonelist *huge_zonelist(struct vm_area_struct *vma, - unsigned long addr, gfp_t gfp_flags); + unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol); extern unsigned slab_node(struct mempolicy *policy); extern enum zone_type policy_zone; @@ -256,7 +256,7 @@ static inline void mpol_fix_fork_child_flag(struct task_struct *p) #define set_cpuset_being_rebound(x) do {} while (0) static inline struct zonelist *huge_zonelist(struct vm_area_struct *vma, - unsigned long addr, gfp_t gfp_flags) + unsigned long addr, gfp_t gfp_flags, struct mempolicy **mpol) { return NODE_DATA(0)->node_zonelists + gfp_zone(gfp_flags); } diff --git a/include/linux/sched.h b/include/linux/sched.h index f4e324ed2e4..5445eaec690 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -593,7 +593,7 @@ struct user_struct { #endif /* Hash table maintenance information */ - struct list_head uidhash_list; + struct hlist_node uidhash_node; uid_t uid; }; @@ -1472,6 +1472,7 @@ static inline struct user_struct *get_uid(struct user_struct *u) } extern void free_uid(struct user_struct *); extern void switch_uid(struct user_struct *); +extern void release_uids(struct user_namespace *ns); #include <asm/current.h> diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 93c27f71122..a656cecd373 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1352,6 +1352,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len) skb_headroom(skb) + len <= skb->hdr_len; } +static inline int __skb_cow(struct sk_buff *skb, unsigned int headroom, + int cloned) +{ + int delta = 0; + + if (headroom < NET_SKB_PAD) + headroom = NET_SKB_PAD; + if (headroom > skb_headroom(skb)) + delta = headroom - skb_headroom(skb); + + if (delta || cloned) + return pskb_expand_head(skb, ALIGN(delta, NET_SKB_PAD), 0, + GFP_ATOMIC); + return 0; +} + /** * skb_cow - copy header of skb when it is required * @skb: buffer to cow @@ -1366,16 +1382,22 @@ static inline int skb_clone_writable(struct sk_buff *skb, int len) */ static inline int skb_cow(struct sk_buff *skb, unsigned int headroom) { - int delta = (headroom > NET_SKB_PAD ? headroom : NET_SKB_PAD) - - skb_headroom(skb); - - if (delta < 0) - delta = 0; + return __skb_cow(skb, headroom, skb_cloned(skb)); +} - if (delta || skb_cloned(skb)) - return pskb_expand_head(skb, (delta + (NET_SKB_PAD-1)) & - ~(NET_SKB_PAD-1), 0, GFP_ATOMIC); - return 0; +/** + * skb_cow_head - skb_cow but only making the head writable + * @skb: buffer to cow + * @headroom: needed headroom + * + * This function is identical to skb_cow except that we replace the + * skb_cloned check by skb_header_cloned. It should be used when + * you only need to push on some header and do not need to modify + * the data. + */ +static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) +{ + return __skb_cow(skb, headroom, skb_header_cloned(skb)); } /** diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h index 1101b0ce878..b5f41d4c2ee 100644 --- a/include/linux/user_namespace.h +++ b/include/linux/user_namespace.h @@ -11,7 +11,7 @@ struct user_namespace { struct kref kref; - struct list_head uidhash_table[UIDHASH_SZ]; + struct hlist_head uidhash_table[UIDHASH_SZ]; struct user_struct *root_user; }; diff --git a/include/media/v4l2-dev.h b/include/media/v4l2-dev.h index d62847f846c..17f8f3a2f0a 100644 --- a/include/media/v4l2-dev.h +++ b/include/media/v4l2-dev.h @@ -337,6 +337,9 @@ void *priv; struct class_device class_dev; /* sysfs */ }; +/* Class-dev to video-device */ +#define to_video_device(cd) container_of(cd, struct video_device, class_dev) + /* Version 2 functions */ extern int video_register_device(struct video_device *vfd, int type, int nr); void video_unregister_device(struct video_device *); @@ -354,11 +357,9 @@ extern int video_usercopy(struct inode *inode, struct file *file, int (*func)(struct inode *inode, struct file *file, unsigned int cmd, void *arg)); - #ifdef CONFIG_VIDEO_V4L1_COMPAT #include <linux/mm.h> -#define to_video_device(cd) container_of(cd, struct video_device, class_dev) static inline int __must_check video_device_create_file(struct video_device *vfd, struct class_device_attribute *attr) diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index d529045c167..c9cc00c8578 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -123,6 +123,7 @@ * sctp/protocol.c */ extern struct sock *sctp_get_ctl_sock(void); +extern void sctp_local_addr_free(struct rcu_head *head); extern int sctp_copy_local_addr_list(struct sctp_bind_addr *, sctp_scope_t, gfp_t gfp, int flags); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index c0d5848c33d..c2fe2dcc9af 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -207,6 +207,9 @@ extern struct sctp_globals { * It is a list of sctp_sockaddr_entry. */ struct list_head local_addr_list; + + /* Lock that protects the local_addr_list writers */ + spinlock_t addr_list_lock; /* Flag to indicate if addip is enabled. */ int addip_enable; @@ -242,6 +245,7 @@ extern struct sctp_globals { #define sctp_port_alloc_lock (sctp_globals.port_alloc_lock) #define sctp_port_hashtable (sctp_globals.port_hashtable) #define sctp_local_addr_list (sctp_globals.local_addr_list) +#define sctp_local_addr_lock (sctp_globals.addr_list_lock) #define sctp_addip_enable (sctp_globals.addip_enable) #define sctp_prsctp_enable (sctp_globals.prsctp_enable) @@ -737,8 +741,10 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk); /* This is a structure for holding either an IPv6 or an IPv4 address. */ struct sctp_sockaddr_entry { struct list_head list; + struct rcu_head rcu; union sctp_addr a; __u8 use_as_src; + __u8 valid; }; typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *); @@ -1149,7 +1155,9 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest, int flags); int sctp_add_bind_addr(struct sctp_bind_addr *, union sctp_addr *, __u8 use_as_src, gfp_t gfp); -int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *); +int sctp_del_bind_addr(struct sctp_bind_addr *, union sctp_addr *, + void (*rcu_call)(struct rcu_head *, + void (*func)(struct rcu_head *))); int sctp_bind_addr_match(struct sctp_bind_addr *, const union sctp_addr *, struct sctp_sock *); union sctp_addr *sctp_find_unmatch_addr(struct sctp_bind_addr *bp, @@ -1220,9 +1228,6 @@ struct sctp_ep_common { * bind_addr.address_list is our set of local IP addresses. */ struct sctp_bind_addr bind_addr; - - /* Protection during address list comparisons. */ - rwlock_t addr_lock; }; |