diff options
Diffstat (limited to 'include/asm-s390')
56 files changed, 2289 insertions, 1135 deletions
diff --git a/include/asm-s390/atomic.h b/include/asm-s390/atomic.h index f1c1f3c5d..d7ced05e8 100644 --- a/include/asm-s390/atomic.h +++ b/include/asm-s390/atomic.h @@ -38,74 +38,80 @@ static __inline__ void atomic_set(atomic_t *v, int i) { __asm__ __volatile__("st %1,%0\n\t" "bcr 15,0" - : : "m" (*v), "d" (i) : "memory"); + : "=m" (*v) : "d" (i) ); } static __inline__ void atomic_add(int i, atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " ar 1,%1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1" ); + : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); } static __inline__ int atomic_add_return (int i, atomic_t *v) { int newval; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ar %1,%2\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b" : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "cc" ); + : "d" (i) : "0", "1", "cc" ); return newval; } static __inline__ int atomic_add_negative(int i, atomic_t *v) { int newval; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ar %1,%2\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b\n" : "+m" (*v), "=&d" (newval) - : "d" (i) : "0", "cc" ); + : "d" (i) : "0", "1", "cc" ); return newval < 0; } static __inline__ void atomic_sub(int i, atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " sr 1,%1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : "d" (i) : "0", "1" ); + : "+m" (*v) : "d" (i) : "0", "1", "2", "cc" ); } static __inline__ void atomic_inc(volatile atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " ahi 1,1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : : "0", "1" ); + : "+m" (*v) : : "0", "1", "2", "cc" ); } static __inline__ int atomic_inc_return(volatile atomic_t *v) { int i; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ahi %1,1\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b" - : "+m" (*v), "=&d" (i) : : "0" ); + : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); return i; } @@ -113,67 +119,74 @@ static __inline__ int atomic_inc_and_test(volatile atomic_t *v) { int i; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ahi %1,1\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b" - : "+m" (*v), "=&d" (i) : : "0" ); + : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); return i != 0; } static __inline__ void atomic_dec(volatile atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " ahi 1,-1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : : "0", "1" ); + : "+m" (*v) : : "0", "1", "2", "cc" ); } static __inline__ int atomic_dec_return(volatile atomic_t *v) { int i; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ahi %1,-1\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b" - : "+m" (*v), "=&d" (i) : : "0" ); + : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); return i; } static __inline__ int atomic_dec_and_test(volatile atomic_t *v) { int i; - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 1,%0\n" + " l 0,%0\n" "0: lr %1,0\n" " ahi %1,-1\n" - " cs 0,%1,%0\n" + " cs 0,%1,0(1)\n" " jl 0b" - : "+m" (*v), "=&d" (i) : : "0"); + : "+m" (*v), "=&d" (i) : : "0", "1", "cc" ); return i == 0; } static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " nr 1,%1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : "d" (~(mask)) : "0", "1" ); + : "+m" (*v) : "d" (~(mask)) + : "0", "1", "2", "cc" ); } static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v) { - __asm__ __volatile__(" l 0,%0\n" + __asm__ __volatile__(" la 2,%0\n" + " l 0,%0\n" "0: lr 1,0\n" " or 1,%1\n" - " cs 0,1,%0\n" + " cs 0,1,0(2)\n" " jl 0b" - : "+m" (*v) : "d" (mask) : "0", "1" ); + : "+m" (*v) : "d" (mask) : "0", "1", "2", "cc" ); } /* @@ -186,13 +199,15 @@ atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v) int retval; __asm__ __volatile__( - " cs %2,%3,%1\n" + " la 1,%1\n" + " lr 0,%2\n" + " cs 0,%3,0(1)\n" " ipm %0\n" " srl %0,28\n" "0:" : "=&r" (retval), "+m" (*v) : "d" (expected_oldval) , "d" (new_val) - : "memory", "cc"); + : "0", "1", "cc"); return retval; } @@ -203,12 +218,20 @@ static __inline__ void atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v) { __asm__ __volatile__( + " la 2,%0\n" "0: lr 1,%1\n" - " cs 1,%2,%0\n" + " cs 1,%2,0(2)\n" " jl 0b\n" : "+m" (*v) : "d" (expected_oldval) , "d" (new_val) - : "memory", "cc", "1"); + : "cc", "1", "2"); +} + +#define atomic_compare_and_swap_debug(where,from,to) \ +if (atomic_compare_and_swap ((from), (to), (where))) {\ + printk (KERN_WARNING"%s/%d atomic counter:%s couldn't be changed from %d(%s) to %d(%s), was %d\n",\ + __FILE__,__LINE__,#where,(from),#from,(to),#to,atomic_read (where));\ + atomic_set(where,(to));\ } #endif /* __ARCH_S390_ATOMIC __ */ diff --git a/include/asm-s390/bitops.h b/include/asm-s390/bitops.h index 710cf8829..f441451c8 100644 --- a/include/asm-s390/bitops.h +++ b/include/asm-s390/bitops.h @@ -41,32 +41,11 @@ extern const char _oi_bitmap[]; extern const char _ni_bitmap[]; extern const char _zb_findmap[]; -/* - * Function prototypes to keep gcc -Wall happy - */ -extern void __set_bit(int nr, volatile void * addr); -extern void __constant_set_bit(int nr, volatile void * addr); -extern int __test_bit(int nr, volatile void * addr); -extern int __constant_test_bit(int nr, volatile void * addr); -extern void __clear_bit(int nr, volatile void * addr); -extern void __constant_clear_bit(int nr, volatile void * addr); -extern void __change_bit(int nr, volatile void * addr); -extern void __constant_change_bit(int nr, volatile void * addr); -extern int test_and_set_bit(int nr, volatile void * addr); -extern int test_and_clear_bit(int nr, volatile void * addr); -extern int test_and_change_bit(int nr, volatile void * addr); -extern int test_and_set_bit_simple(int nr, volatile void * addr); -extern int test_and_clear_bit_simple(int nr, volatile void * addr); -extern int test_and_change_bit_simple(int nr, volatile void * addr); -extern int find_first_zero_bit(void * addr, unsigned size); -extern int find_next_zero_bit (void * addr, int size, int offset); -extern unsigned long ffz(unsigned long word); - #ifdef CONFIG_SMP /* * SMP save set_bit routine based on compare and swap (CS) */ -extern __inline__ void set_bit_cs(int nr, volatile void * addr) +static __inline__ void set_bit_cs(int nr, volatile void * addr) { __asm__ __volatile__( #if ALIGN_CS == 1 @@ -80,8 +59,8 @@ extern __inline__ void set_bit_cs(int nr, volatile void * addr) " nr 1,%0\n" /* make shift value */ " xr %0,1\n" " srl %0,3\n" - " la %1,0(%0,%1)\n" /* calc. address for CS */ " lhi 2,1\n" + " la %1,0(%0,%1)\n" /* calc. address for CS */ " sll 2,0(1)\n" /* make OR mask */ " l %0,0(%1)\n" "0: lr 1,%0\n" /* CS loop starts here */ @@ -95,7 +74,7 @@ extern __inline__ void set_bit_cs(int nr, volatile void * addr) /* * SMP save clear_bit routine based on compare and swap (CS) */ -extern __inline__ void clear_bit_cs(int nr, volatile void * addr) +static __inline__ void clear_bit_cs(int nr, volatile void * addr) { static const int mask = -1; __asm__ __volatile__( @@ -110,8 +89,8 @@ extern __inline__ void clear_bit_cs(int nr, volatile void * addr) " nr 1,%0\n" /* make shift value */ " xr %0,1\n" " srl %0,3\n" - " la %1,0(%0,%1)\n" /* calc. address for CS */ " lhi 2,1\n" + " la %1,0(%0,%1)\n" /* calc. address for CS */ " sll 2,0(1)\n" " x 2,%2\n" /* make AND mask */ " l %0,0(%1)\n" @@ -126,7 +105,7 @@ extern __inline__ void clear_bit_cs(int nr, volatile void * addr) /* * SMP save change_bit routine based on compare and swap (CS) */ -extern __inline__ void change_bit_cs(int nr, volatile void * addr) +static __inline__ void change_bit_cs(int nr, volatile void * addr) { __asm__ __volatile__( #if ALIGN_CS == 1 @@ -140,8 +119,8 @@ extern __inline__ void change_bit_cs(int nr, volatile void * addr) " nr 1,%0\n" /* make shift value */ " xr %0,1\n" " srl %0,3\n" - " la %1,0(%0,%1)\n" /* calc. address for CS */ " lhi 2,1\n" + " la %1,0(%0,%1)\n" /* calc. address for CS */ " sll 2,0(1)\n" /* make XR mask */ " l %0,0(%1)\n" "0: lr 1,%0\n" /* CS loop starts here */ @@ -155,7 +134,7 @@ extern __inline__ void change_bit_cs(int nr, volatile void * addr) /* * SMP save test_and_set_bit routine based on compare and swap (CS) */ -extern __inline__ int test_and_set_bit_cs(int nr, volatile void * addr) +static __inline__ int test_and_set_bit_cs(int nr, volatile void * addr) { __asm__ __volatile__( #if ALIGN_CS == 1 @@ -186,7 +165,7 @@ extern __inline__ int test_and_set_bit_cs(int nr, volatile void * addr) /* * SMP save test_and_clear_bit routine based on compare and swap (CS) */ -extern __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr) +static __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr) { static const int mask = -1; __asm__ __volatile__( @@ -220,7 +199,7 @@ extern __inline__ int test_and_clear_bit_cs(int nr, volatile void * addr) /* * SMP save test_and_change_bit routine based on compare and swap (CS) */ -extern __inline__ int test_and_change_bit_cs(int nr, volatile void * addr) +static __inline__ int test_and_change_bit_cs(int nr, volatile void * addr) { __asm__ __volatile__( #if ALIGN_CS == 1 @@ -252,7 +231,7 @@ extern __inline__ int test_and_change_bit_cs(int nr, volatile void * addr) /* * fast, non-SMP set_bit routine */ -extern __inline__ void __set_bit(int nr, volatile void * addr) +static __inline__ void __set_bit(int nr, volatile void * addr) { __asm__ __volatile__( " lhi 2,24\n" @@ -267,7 +246,7 @@ extern __inline__ void __set_bit(int nr, volatile void * addr) : "cc", "memory", "1", "2" ); } -extern __inline__ void +static __inline__ void __constant_set_bit(const int nr, volatile void * addr) { switch (nr&7) { @@ -330,7 +309,7 @@ __constant_set_bit(const int nr, volatile void * addr) /* * fast, non-SMP clear_bit routine */ -extern __inline__ void +static __inline__ void __clear_bit(int nr, volatile void * addr) { __asm__ __volatile__( @@ -346,7 +325,7 @@ __clear_bit(int nr, volatile void * addr) : "cc", "memory", "1", "2" ); } -extern __inline__ void +static __inline__ void __constant_clear_bit(const int nr, volatile void * addr) { switch (nr&7) { @@ -409,7 +388,7 @@ __constant_clear_bit(const int nr, volatile void * addr) /* * fast, non-SMP change_bit routine */ -extern __inline__ void __change_bit(int nr, volatile void * addr) +static __inline__ void __change_bit(int nr, volatile void * addr) { __asm__ __volatile__( " lhi 2,24\n" @@ -424,7 +403,7 @@ extern __inline__ void __change_bit(int nr, volatile void * addr) : "cc", "memory", "1", "2" ); } -extern __inline__ void +static __inline__ void __constant_change_bit(const int nr, volatile void * addr) { switch (nr&7) { @@ -487,7 +466,7 @@ __constant_change_bit(const int nr, volatile void * addr) /* * fast, non-SMP test_and_set_bit routine */ -extern __inline__ int test_and_set_bit_simple(int nr, volatile void * addr) +static __inline__ int test_and_set_bit_simple(int nr, volatile void * addr) { static const int mask = 1; int oldbit; @@ -512,7 +491,7 @@ extern __inline__ int test_and_set_bit_simple(int nr, volatile void * addr) /* * fast, non-SMP test_and_clear_bit routine */ -extern __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr) +static __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr) { static const int mask = 1; int oldbit; @@ -538,7 +517,7 @@ extern __inline__ int test_and_clear_bit_simple(int nr, volatile void * addr) /* * fast, non-SMP test_and_change_bit routine */ -extern __inline__ int test_and_change_bit_simple(int nr, volatile void * addr) +static __inline__ int test_and_change_bit_simple(int nr, volatile void * addr) { static const int mask = 1; int oldbit; @@ -582,7 +561,7 @@ extern __inline__ int test_and_change_bit_simple(int nr, volatile void * addr) * This routine doesn't need to be atomic. */ -extern __inline__ int __test_bit(int nr, volatile void * addr) +static __inline__ int __test_bit(int nr, volatile void * addr) { static const int mask = 1; int oldbit; @@ -602,7 +581,7 @@ extern __inline__ int __test_bit(int nr, volatile void * addr) return oldbit; } -extern __inline__ int __constant_test_bit(int nr, volatile void * addr) { +static __inline__ int __constant_test_bit(int nr, volatile void * addr) { return (((volatile char *) addr)[(nr>>3)^3] & (1<<(nr&7))) != 0; } @@ -614,7 +593,7 @@ extern __inline__ int __constant_test_bit(int nr, volatile void * addr) { /* * Find-bit routines.. */ -extern __inline__ int find_first_zero_bit(void * addr, unsigned size) +static __inline__ int find_first_zero_bit(void * addr, unsigned size) { static const int mask = 0xffL; int res; @@ -633,7 +612,7 @@ extern __inline__ int find_first_zero_bit(void * addr, unsigned size) " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" " tml 1,0xFFFF\n" " jno 2f\n" " ahi 2,16\n" @@ -653,7 +632,7 @@ extern __inline__ int find_first_zero_bit(void * addr, unsigned size) return (res < size) ? res : size; } -extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) +static __inline__ int find_next_zero_bit (void * addr, int size, int offset) { static const int mask = 0xffL; unsigned long * p = ((unsigned long *) addr) + (offset >> 5); @@ -698,7 +677,7 @@ extern __inline__ int find_next_zero_bit (void * addr, int size, int offset) * ffz = Find First Zero in word. Undefined if no zero exists, * so code should check against ~0UL first.. */ -extern __inline__ unsigned long ffz(unsigned long word) +static __inline__ unsigned long ffz(unsigned long word) { static const int mask = 0xffL; int result; @@ -738,24 +717,24 @@ extern int __inline__ ffs (int x) return 0; __asm__(" lr %%r1,%1\n" " sr %0,%0\n" - " tmh %%r1,0xFFFF\n" - " jz 0f\n" + " tml %%r1,0xFFFF\n" + " jnz 0f\n" " ahi %0,16\n" " srl %%r1,16\n" - "0: tml %%r1,0xFF00\n" - " jz 1f\n" + "0: tml %%r1,0x00FF\n" + " jnz 1f\n" " ahi %0,8\n" " srl %%r1,8\n" - "1: tml %%r1,0x00F0\n" - " jz 2f\n" + "1: tml %%r1,0x000F\n" + " jnz 2f\n" " ahi %0,4\n" " srl %%r1,4\n" - "2: tml %%r1,0x000C\n" - " jz 3f\n" + "2: tml %%r1,0x0003\n" + " jnz 3f\n" " ahi %0,2\n" " srl %%r1,2\n" - "3: tml %%r1,0x0002\n" - " jz 4f\n" + "3: tml %%r1,0x0001\n" + " jnz 4f\n" " ahi %0,1\n" "4:" : "=&d" (r) : "d" (x) : "cc", "1" ); @@ -787,9 +766,8 @@ extern int __inline__ ffs (int x) #define ext2_set_bit(nr, addr) test_and_set_bit((nr)^24, addr) #define ext2_clear_bit(nr, addr) test_and_clear_bit((nr)^24, addr) #define ext2_test_bit(nr, addr) test_bit((nr)^24, addr) -extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size) +static __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size) { - static const int mask = 0xffL; int res; if (!size) @@ -806,7 +784,8 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size) " lr 2,%1\n" " j 4f\n" "1: l 1,0(2,%2)\n" - " sll 2,3(0)\n" + " sll 2,3\n" + " lhi 0,0xff\n" " ahi 2,24\n" " tmh 1,0xFFFF\n" " jo 2f\n" @@ -816,31 +795,19 @@ extern __inline__ int ext2_find_first_zero_bit(void *vaddr, unsigned size) " jo 3f\n" " ahi 2,-8\n" " srl 1,8\n" - "3: n 1,%3\n" - " ic 1,0(1,%4)\n" - " n 1,%3\n" + "3: nr 1,0\n" + " ic 1,0(1,%3)\n" " ar 2,1\n" "4: lr %0,2" : "=d" (res) : "a" (size), "a" (vaddr), - "m" (mask), "a" (&_zb_findmap) + "a" (&_zb_findmap) : "cc", "0", "1", "2" ); return (res < size) ? res : size; } -extern __inline__ int +static __inline__ int ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset) { - static const int mask = 0xffL; - static unsigned long orword[32] = { - 0x00000000, 0x01000000, 0x03000000, 0x07000000, - 0x0f000000, 0x1f000000, 0x3f000000, 0x7f000000, - 0xff000000, 0xff010000, 0xff030000, 0xff070000, - 0xff0f0000, 0xff1f0000, 0xff3f0000, 0xff7f0000, - 0xffff0000, 0xffff0100, 0xffff0300, 0xffff0700, - 0xffff0f00, 0xffff1f00, 0xffff3f00, 0xffff7f00, - 0xffffff00, 0xffffff01, 0xffffff03, 0xffffff07, - 0xffffff0f, 0xffffff1f, 0xffffff3f, 0xffffff7f - }; unsigned long *addr = vaddr; unsigned long *p = addr + (offset >> 5); unsigned long word; @@ -850,23 +817,29 @@ ext2_find_next_zero_bit(void *vaddr, unsigned size, unsigned offset) return size; if (bit) { - word = *p | orword[bit]; + __asm__(" ic %0,0(%1)\n" + " icm %0,2,1(%1)\n" + " icm %0,4,2(%1)\n" + " icm %0,8,3(%1)" + : "=&a" (word) : "a" (p) ); + word >>= bit; + res = bit; /* Look for zero in first longword */ - __asm__(" lhi %0,24\n" - " tmh %1,0xFFFF\n" - " jo 0f\n" - " ahi %0,-16\n" + __asm__(" lhi 0,0xff\n" + " tml %1,0xffff\n" + " jno 0f\n" + " ahi %0,16\n" " srl %1,16\n" - "0: tml %1,0xFF00\n" - " jo 1f\n" - " ahi %0,-8\n" + "0: tml %1,0x00ff\n" + " jno 1f\n" + " ahi %0,8\n" " srl %1,8\n" - "1: n %1,%2\n" - " ic %1,0(%1,%3)\n" + "1: nr %1,0\n" + " ic %1,0(%1,%2)\n" " alr %0,%1" - : "=&d" (res), "+&d" (word) - : "m" (mask), "a" (&_zb_findmap) - : "cc" ); + : "+&d" (res), "+&a" (word) + : "a" (&_zb_findmap) + : "cc", "0" ); if (res < 32) return (p - addr)*32 + res; p++; diff --git a/include/asm-s390/ccwcache.h b/include/asm-s390/ccwcache.h new file mode 100644 index 000000000..cfbb03bf2 --- /dev/null +++ b/include/asm-s390/ccwcache.h @@ -0,0 +1,84 @@ +/* + * File...........: linux/include/asm-s390/ccwcache.h + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000 + */ +#ifndef CCWCACHE_H +#define CCWCACHE_H +#include <linux/slab.h> +#include <asm/irq.h> + +#ifndef __KERNEL__ +#define kmem_cache_t void +#endif /* __KERNEL__ */ + +typedef struct ccw_req_t { + /* eye catcher plus queueing information */ + unsigned int magic; + struct ccw_req_t *next; /* pointer to next ccw_req_t in queue */ + struct ccw_req_t *int_next; /* for internal queueing */ + struct ccw_req_t *int_prev; /* for internal queueing */ + + /* Where to execute what... */ + void *device; /* index of the device the req is for */ + void *req; /* pointer to originating request */ + ccw1_t *cpaddr; /* address of channel program */ + char status; /* reflecting the status of this request */ + char flags; /* see below */ + short retries; /* A retry counter to be set when filling */ + + /* ... and how */ + int options; /* options for execution */ + char lpm; /* logical path mask */ + void *data; /* pointer to data area */ + devstat_t *dstat; /* The device status in case of an error */ + + /* these are important for recovering erroneous requests */ + struct ccw_req_t *refers; /* Does this request refer to another one? */ + void *function; /* refers to the originating ERP action */ ; + + unsigned long long expires; /* expiratioj period */ + /* these are for profiling purposes */ + unsigned long long buildclk; /* TOD-clock of request generation */ + unsigned long long startclk; /* TOD-clock of request start */ + unsigned long long stopclk; /* TOD-clock of request interrupt */ + unsigned long long endclk; /* TOD-clock of request termination */ + + /* these are for internal use */ + int cplength; /* length of the channel program in CCWs */ + int datasize; /* amount of additional data in bytes */ + kmem_cache_t *cache; /* the cache this data comes from */ + +} __attribute__ ((aligned(4))) ccw_req_t; + +/* + * ccw_req_t -> status can be: + */ +#define CQR_STATUS_EMPTY 0x00 /* request is empty */ +#define CQR_STATUS_FILLED 0x01 /* request is ready to be preocessed */ +#define CQR_STATUS_QUEUED 0x02 /* request is queued to be processed */ +#define CQR_STATUS_IN_IO 0x03 /* request is currently in IO */ +#define CQR_STATUS_DONE 0x04 /* request is completed sucessfully */ +#define CQR_STATUS_ERROR 0x05 /* request is completed with error */ +#define CQR_STATUS_FAILED 0x06 /* request is finally failed */ + +#define CQR_FLAGS_CHAINED 0x01 /* request is chained by another (last CCW is TIC) */ + +#ifdef __KERNEL__ +#define SMALLEST_SLAB (sizeof(struct ccw_req_t) <= 128 ? 128 :\ + sizeof(struct ccw_req_t) <= 256 ? 256 : 512 ) + +/* SMALLEST_SLAB(1),... PAGE_SIZE(CCW_NUMBER_CACHES) */ +#define CCW_NUMBER_CACHES (sizeof(struct ccw_req_t) <= 128 ? 6 :\ + sizeof(struct ccw_req_t) <= 256 ? 5 : 4 ) + +int ccwcache_init (void); + +ccw_req_t *ccw_alloc_request (char *magic, int cplength, int additional_data); +void ccw_free_request (ccw_req_t * request); +#endif /* __KERNEL__ */ +#endif /* CCWCACHE_H */ + + + diff --git a/include/asm-s390/chandev.h b/include/asm-s390/chandev.h index c9e7d2d54..9efb6fea3 100644 --- a/include/asm-s390/chandev.h +++ b/include/asm-s390/chandev.h @@ -1,87 +1,151 @@ /* * include/asm-s390/chandev.h * - * S390 version * Copyright (C) 2000 IBM Deutschland Entwicklung GmbH, IBM Corporation * Author(s): Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com) - * + * + * Generic channel device initialisation support. */ - +#include <linux/version.h> #include <asm/types.h> +#include <linux/netdevice.h> +/* chandev_type is a bitmask for registering & describing device types. */ typedef enum { - none=0, - ctc=1, - escon=2, - lcs=4, - osad=8, - claw=16, + none=0x0, + ctc=0x1, + escon=0x2, + lcs=0x4, + osad=0x8, + qeth=0x10, + claw=0x20, } chandev_type; -typedef struct chandev_model_info chandev_model_info; - -struct chandev_model_info -{ - struct chandev_model_info *next; - chandev_type chan_type; - u16 cu_type; - u8 cu_model; - u8 max_port_no; -}; - -typedef struct chandev chandev; -struct chandev -{ - struct chandev *next; - chandev_model_info *model_info; - u16 devno; - int irq; -}; - -typedef struct chandev_noauto_range chandev_noauto_range; -struct chandev_noauto_range -{ - struct chandev_noauto_range *next; - u16 lo_devno; - u16 hi_devno; -}; - -typedef struct chandev_force chandev_force; -struct chandev_force +typedef enum { - struct chandev_force *next; - chandev_type chan_type; - s32 devif_num; /* -1 don't care e.g. tr0 implies 0 */ - u16 read_devno; - u16 write_devno; - s16 port_no; /* where available e.g. lcs,-1 don't care */ - u8 do_ip_checksumming; - u8 use_hw_stats; /* where available e.g. lcs */ -}; - - + no_category, + network_device, + serial_device, +} chandev_category; +/* + * The chandev_probeinfo structure is passed to the device driver with configuration + * info for which irq's & ports to use when attempting to probe the device. + */ typedef struct { - s32 devif_num; /* -1 don't care e.g. tr0 implies 0 */ int read_irq; int write_irq; - s16 forced_port_no; /* -1 don't care */ - u8 hint_port_no; - u8 max_port_no; - u8 do_ip_checksumming; + u16 read_devno; + u16 write_devno; + s16 port_protocol_no; /* -1 don't care */ + u8 hint_port_no; /* lcs specific */ + u8 max_port_no; /* lcs specific */ + chandev_type chan_type; + u8 checksum_received_ip_pkts; u8 use_hw_stats; /* where available e.g. lcs */ + u16 cu_type; /* control unit type */ + u8 cu_model; /* control unit model */ + u16 dev_type; /* device type */ + u8 dev_model; /* device model */ + char *parmstr; /* driver specific parameters added by add_parms keyword */ + /* newdevice used internally by chandev.c */ + struct chandev_activelist *newdevice; + s32 devif_num; +/* devif_num=-1 implies don't care,0 implies tr0, info used by chandev_initnetdevice */ } chandev_probeinfo; +/* + * This is a wrapper to the machine check handler & should be used + * instead of reqest_irq or s390_request_irq_special for anything + * using the channel device layer. + */ +int chandev_request_irq(unsigned int irq, + void (*handler)(int, void *, struct pt_regs *), + unsigned long irqflags, + const char *devname, + void *dev_id); + +typedef enum +{ + good=0, + not_oper, + first_msck=not_oper, + no_path, + revalidate, + gone, + last_msck, +} chandev_msck_status; typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo); +typedef void (*chandev_shutdownfunc)(void *device); +typedef void (*chandev_unregfunc)(void *device); +typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus); + + + +/* A driver should call chandev_register_and_probe when ready to be probed, + * after registeration the drivers probefunction will be called asynchronously + * when more devices become available at normal task time. + * The shutdownfunc parameter is used so that the channel layer + * can request a driver to close unregister itself & release its interrupts. + * repoper func is used when a device becomes operational again after being temporarily + * not operational the previous status is sent in the prevstatus variable. + * This can be used in cases when the default handling isn't quite adequete + * e.g. if a ssch is needed to reinitialize long running channel programs. + */ +int chandev_register_and_probe(chandev_probefunc probefunc, + chandev_shutdownfunc shutdownfunc, + chandev_reoperfunc reoperfunc, + chandev_type chan_type); + +/* The chandev_unregister function is typically called when a module is being removed + * from the system. The shutdown parameter if TRUE calls shutdownfunc for each + * device instance so the driver writer doesn't have to. + */ +void chandev_unregister(chandev_probefunc probefunc,int call_shutdown); + +/* chandev_initdevice should be called immeadiately before returning after */ +/* a successful probe. */ +int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname, +chandev_category category,chandev_unregfunc unreg_dev); + +/* chandev_initnetdevice registers a network device with the channel layer. + * It returns the device structure if successful,if dev=NULL it kmallocs it, + * On device initialisation failure it will kfree it under ALL curcumstances + * i.e. if dev is not NULL on entering this routine it MUST be malloced with kmalloc. + * The base name is tr ( e.g. tr0 without the 0 ), for token ring eth for ethernet, + * ctc or escon for ctc device drivers. + * If valid function pointers are given they will be called to setup, + * register & unregister the device. + * An example of setup is eth_setup in drivers/net/net_init.c. + * An example of init_dev is init_trdev(struct net_device *dev) + * & an example of unregister is unregister_trdev, + * unregister_netdev should be used for escon & ctc + * as there is no network unregister_ctcdev in the kernel. +*/ + +#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0) +struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no, + struct net_device *dev,int sizeof_priv, + char *basename, + struct net_device *(*init_netdevfunc) + (struct net_device *dev, int sizeof_priv), + void (*unreg_netdevfunc)(struct net_device *dev)); +#else +struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no, + struct device *dev,int sizeof_priv, + char *basename, + struct device *(*init_netdevfunc) + (struct device *dev, int sizeof_priv), + void (*unreg_netdevfunc)(struct device *dev)); +#endif + + + + + + -typedef struct chandev_probelist chandev_probelist; -struct chandev_probelist -{ - struct chandev_probelist *next; - chandev_probefunc probefunc; - chandev_type chan_type; -}; diff --git a/include/asm-s390/checksum.h b/include/asm-s390/checksum.h index 487ccc99b..cd0159a5b 100644 --- a/include/asm-s390/checksum.h +++ b/include/asm-s390/checksum.h @@ -141,20 +141,19 @@ csum_tcpudp_nofold(unsigned long saddr, unsigned long daddr, unsigned int sum) { __asm__ __volatile__ ( - " sll %3,16\n" - " or %3,%4\n" /* newproto=proto<<16 in hiword, len in lowword */ - " alr %1,%2\n" /* saddr+=daddr */ - " brc 12,0f\n" - " ahi %1,1\n" /* add carry */ - "0: alr %1,%3\n" /* add saddr+=newproto */ - " brc 12,1f\n" - " ahi %1,1\n" /* add carry again */ - "1: alr %0,%1\n" /* sum+=saddr */ + " alr %0,%1\n" /* sum += saddr */ + " brc 12,0f\n" + " ahi %0,1\n" /* add carry */ + "0: alr %0,%2\n" /* sum += daddr */ + " brc 12,1f\n" + " ahi %0,1\n" /* add carry */ + "1: alr %0,%3\n" /* sum += (len<<16) + (proto<<8) */ " brc 12,2f\n" - " ahi %0,1\n" /* add carry again */ + " ahi %0,1\n" /* add carry */ "2:" : "+&d" (sum) - : "d" (saddr), "d" (daddr), "d" (proto), "d" (len) + : "d" (saddr), "d" (daddr), + "d" (((unsigned int) len<<16) + (unsigned int) proto) : "cc" ); return sum; } diff --git a/include/asm-s390/current.h b/include/asm-s390/current.h index 42567eb94..88e8fc04e 100644 --- a/include/asm-s390/current.h +++ b/include/asm-s390/current.h @@ -20,7 +20,7 @@ static inline struct task_struct * get_current(void) struct task_struct *current; __asm__("lhi %0,-8192\n\t" "nr %0,15" - : "=r" (current) ); + : "=&r" (current) ); return current; } diff --git a/include/asm-s390/dasd.h b/include/asm-s390/dasd.h new file mode 100644 index 000000000..ea5e43eae --- /dev/null +++ b/include/asm-s390/dasd.h @@ -0,0 +1,339 @@ +/* + * File...........: linux/drivers/s390/block/dasd.c + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + */ + +#ifndef DASD_H +#define DASD_H + +#include <linux/ioctl.h> +#include <asm/irq.h> + +#define IOCTL_LETTER 'D' +/* Disable the volume (for Linux) */ +#define BIODASDDISABLE _IO(IOCTL_LETTER,0) +/* Enable the volume (for Linux) */ +#define BIODASDENABLE _IO(IOCTL_LETTER,1) +/* Issue a reserve/release command, rsp. */ +#define BIODASDRSRV _IO(IOCTL_LETTER,2) /* reserve */ +#define BIODASDRLSE _IO(IOCTL_LETTER,3) /* release */ +#define BIODASDSLCK _IO(IOCTL_LETTER,4) /* steal lock */ +/* Read sense ID infpormation */ +#define BIODASDRSID _IOR(IOCTL_LETTER,0,senseid_t) +/* Format the volume or an extent */ +#define BIODASDFORMAT _IOW(IOCTL_LETTER,0,format_data_t) +/* translate blocknumber of partition to absolute */ +#define BIODASDRWTB _IOWR(IOCTL_LETTER,0,int) + +#define DASD_NAME "dasd" +#define DASD_PARTN_BITS 2 +#define DASD_PER_MAJOR ( 1U<<(MINORBITS-DASD_PARTN_BITS)) + +/* + * struct format_data_t + * represents all data necessary to format a dasd + */ +typedef struct format_data_t { + int start_unit; /* from track */ + int stop_unit; /* to track */ + int blksize; /* sectorsize */ + int intensity; /* 0: normal, 1:record zero, 3:home address, 4 invalidate tracks */ +} __attribute__ ((packed)) format_data_t; + +#define DASD_FORMAT_DEFAULT_START_UNIT 0 +#define DASD_FORMAT_DEFAULT_STOP_UNIT -1 +#define DASD_FORMAT_DEFAULT_BLOCKSIZE -1 +#define DASD_FORMAT_DEFAULT_INTENSITY -1 + +#ifdef __KERNEL__ +#include <linux/version.h> +#include <linux/major.h> +#include <linux/wait.h> +#include <asm/ccwcache.h> +#include <linux/blk.h> +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) +#include <linux/blkdev.h> +#include <linux/devfs_fs_kernel.h> +#endif +#include <linux/genhd.h> +#include <linux/hdreg.h> +#include <linux/compatmac.h> + +#include <asm/s390dyn.h> +#include <asm/todclk.h> +#include <asm/debug.h> + +/* Kernel Version Compatibility section */ +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98)) +typedef struct request *request_queue_t; +#define block_device_operations file_operations +#define __setup(x,y) struct dasd_device_t +#define devfs_register_blkdev(major,name,ops) register_blkdev(major,name,ops) +#define register_disk(dd,dev,partn,ops,size) \ +do { \ + dd->sizes[MINOR(dev)] = size >> 1; \ + resetup_one_dev(dd,MINOR(dev)>>DASD_PARTN_BITS); \ +} while(0) +#define init_waitqueue_head(x) do { *x = NULL; } while(0) +#define blk_cleanup_queue(x) do {} while(0) +#define blk_init_queue(x...) do {} while(0) +#define blk_queue_headactive(x...) do {} while(0) +#define blk_queue_make_request(x) do {} while(0) +#define list_empty(x) (0) +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].request_fn = d_request_fn; \ + blk_dev[d_major].queue = d_queue_fn; \ + blk_dev[d_major].current_request = d_current; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + max_nr:D_PER_MAJOR, \ + nr_real:D_PER_MAJOR, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return *queue; +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + *q = req->next; + req->next = NULL; +} +#else +#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \ +do { \ + blk_dev[d_major].queue = d_queue_fn; \ +} while(0) +#define INIT_GENDISK(D_MAJOR,D_NAME,D_PARTN_BITS,D_PER_MAJOR) \ + major:D_MAJOR, \ + major_name:D_NAME, \ + minor_shift:D_PARTN_BITS, \ + max_p:1 << D_PARTN_BITS, \ + nr_real:D_PER_MAJOR, +static inline struct request * +dasd_next_request( request_queue_t *queue ) +{ + return blkdev_entry_next_request(&queue->queue_head); +} +static inline void +dasd_dequeue_request( request_queue_t * q, struct request *req ) +{ + blkdev_dequeue_request (req); +} +#endif + +/* dasd_range_t are used for dynamic device att-/detachment */ +typedef struct dasd_devreg_t { + devreg_t devreg; /* the devreg itself */ + /* build a linked list of devregs, needed for cleanup */ + struct dasd_devreg_t *next; +} dasd_devreg_t; + +typedef enum { + dasd_era_fatal = -1, /* no chance to recover */ + dasd_era_none = 0, /* don't recover, everything alright */ + dasd_era_msg = 1, /* don't recover, just report... */ + dasd_era_recover = 2 /* recovery action recommended */ +} dasd_era_t; + +/* BIT DEFINITIONS FOR SENSE DATA */ +#define DASD_SENSE_BIT_0 0x80 +#define DASD_SENSE_BIT_1 0x40 +#define DASD_SENSE_BIT_2 0x20 +#define DASD_SENSE_BIT_3 0x10 + +#define check_then_set(where,from,to) \ +do { \ + if ((*(where)) != (from) ) { \ + printk (KERN_ERR PRINTK_HEADER "was %d\n", *(where)); \ + BUG(); \ + } \ + (*(where)) = (to); \ +} while (0) + +#define DASD_MESSAGE(d_loglevel,d_device,d_string,d_args...)\ +do { \ + int d_devno = d_device->devinfo.devno; \ + int d_irq = d_device->devinfo.irq; \ + char *d_name = d_device->name; \ + int d_major = MAJOR(d_device->kdev); \ + int d_minor = MINOR(d_device->kdev); \ + printk(d_loglevel PRINTK_HEADER \ + "/dev/%s(%d:%d), 0x%04X on SCH 0x%x:" \ + d_string "\n",d_name,d_major,d_minor,d_devno,d_irq,d_args ); \ +} while(0) + +/* + * struct dasd_sizes_t + * represents all data needed to access dasd with properly set up sectors + */ +typedef +struct dasd_sizes_t { + unsigned long blocks; /* size of volume in blocks */ + unsigned int bp_block; /* bytes per block */ + unsigned int s2b_shift; /* log2 (bp_block/512) */ +} dasd_sizes_t; + +/* + * struct dasd_chanq_t + * represents a queue of channel programs related to a single device + */ +typedef +struct dasd_chanq_t { + ccw_req_t *head; + ccw_req_t *tail; +} dasd_chanq_t; + +struct dasd_device_t; +struct request; + +/* + * signatures for the functions of dasd_discipline_t + * make typecasts much easier + */ +typedef ccw_req_t *(*dasd_erp_action_fn_t) (ccw_req_t * cqr); +typedef ccw_req_t *(*dasd_erp_postaction_fn_t) (ccw_req_t * cqr); + +typedef int (*dasd_ck_id_fn_t) (s390_dev_info_t *); +typedef int (*dasd_ck_characteristics_fn_t) (struct dasd_device_t *); +typedef int (*dasd_fill_geometry_fn_t) (struct dasd_device_t *, struct hd_geometry *); +typedef ccw_req_t *(*dasd_format_fn_t) (struct dasd_device_t *, struct format_data_t *); +typedef ccw_req_t *(*dasd_init_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_do_analysis_fn_t) (struct dasd_device_t *); +typedef int (*dasd_io_starter_fn_t) (ccw_req_t *); +typedef void (*dasd_int_handler_fn_t)(int irq, void *, struct pt_regs *); +typedef dasd_era_t (*dasd_error_examine_fn_t) (ccw_req_t *, devstat_t * stat); +typedef dasd_erp_action_fn_t (*dasd_error_analyse_fn_t) (ccw_req_t *); +typedef dasd_erp_postaction_fn_t (*dasd_erp_analyse_fn_t) (ccw_req_t *); +typedef ccw_req_t *(*dasd_cp_builder_fn_t)(struct dasd_device_t *,struct request *); +typedef char *(*dasd_dump_sense_fn_t)(struct dasd_device_t *,ccw_req_t *); +typedef ccw_req_t *(*dasd_reserve_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_release_fn_t)(struct dasd_device_t *); +typedef ccw_req_t *(*dasd_merge_cp_fn_t)(struct dasd_device_t *); + + +/* + * the dasd_discipline_t is + * sth like a table of virtual functions, if you think of dasd_eckd + * inheriting dasd... + * no, currently we are not planning to reimplement the driver in C++ + */ +typedef struct dasd_discipline_t { + char ebcname[8]; /* a name used for tagging and printks */ + char name[8]; /* a name used for tagging and printks */ + + dasd_ck_id_fn_t id_check; /* to check sense data */ + dasd_ck_characteristics_fn_t check_characteristics; /* to check the characteristics */ + dasd_init_analysis_fn_t init_analysis; /* to start the analysis of the volume */ + dasd_do_analysis_fn_t do_analysis; /* to complete the analysis of the volume */ + dasd_fill_geometry_fn_t fill_geometry; /* to set up hd_geometry */ + dasd_io_starter_fn_t start_IO; + dasd_format_fn_t format_device; /* to format the device */ + dasd_error_examine_fn_t examine_error; + dasd_error_analyse_fn_t erp_action; + dasd_erp_analyse_fn_t erp_postaction; + dasd_cp_builder_fn_t build_cp_from_req; + dasd_dump_sense_fn_t dump_sense; + dasd_int_handler_fn_t int_handler; + dasd_reserve_fn_t reserve; + dasd_release_fn_t release; + dasd_merge_cp_fn_t merge_cp; + + struct dasd_discipline_t *next; /* used for list of disciplines */ +} dasd_discipline_t; + +typedef struct major_info_t { + struct major_info_t *next; + struct dasd_device_t **dasd_device; + struct gendisk gendisk; /* actually contains the major number */ +} __attribute__ ((packed)) major_info_t; + +typedef struct dasd_profile_info_t { + unsigned long dasd_io_reqs; /* number of requests processed at all */ + unsigned long dasd_io_secs[32]; /* histogram of request's sizes */ + unsigned long dasd_io_times[32]; /* histogram of requests's times */ + unsigned long dasd_io_timps[32]; /* histogram of requests's times per sector */ + unsigned long dasd_io_time1[32]; /* histogram of time from build to start */ + unsigned long dasd_io_time2[32]; /* histogram of time from start to irq */ + unsigned long dasd_io_time2ps[32]; /* histogram of time from start to irq */ + unsigned long dasd_io_time3[32]; /* histogram of time from irq to end */ +} dasd_profile_info_t; + +typedef struct dasd_device_t { + s390_dev_info_t devinfo; + dasd_discipline_t *discipline; + int level; + int open_count; + kdev_t kdev; + major_info_t *major_info; + struct dasd_chanq_t queue; + wait_queue_head_t wait_q; + request_queue_t request_queue; + devstat_t dev_status; /* needed ONLY!! for request_irq */ + dasd_sizes_t sizes; + char name[16]; /* The name of the device in /dev */ + char *private; /* to be used by the discipline internally */ +#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98)) + devfs_handle_t devfs_entry; +#endif /* LINUX_IS_24 */ + struct tq_struct bh_tq; + atomic_t bh_scheduled; + debug_info_t *debug_area; + dasd_profile_info_t profile; + struct proc_dir_entry *proc_dir; /* directory node */ + struct proc_dir_entry *proc_info; /* information from dasd_device_t */ + struct proc_dir_entry *proc_stats; /* statictics information */ +} dasd_device_t; + +/* dasd_device_t.level can be: */ +#define DASD_DEVICE_LEVEL_UNKNOWN 0x00 +#define DASD_DEVICE_LEVEL_RECOGNIZED 0x01 +#define DASD_DEVICE_LEVEL_ANALYSIS_PENDING 0x02 +#define DASD_DEVICE_LEVEL_ANALYSIS_PREPARED 0x04 +#define DASD_DEVICE_LEVEL_ANALYSED 0x08 +#define DASD_DEVICE_LEVEL_PARTITIONED 0x10 + +int dasd_init (void); +void dasd_discipline_enq (dasd_discipline_t *); +int dasd_discipline_deq(dasd_discipline_t *); +int dasd_start_IO (ccw_req_t *); +void dasd_int_handler (int , void *, struct pt_regs *); +ccw_req_t *default_erp_action (ccw_req_t *); +ccw_req_t *default_erp_postaction (ccw_req_t *); +int dasd_chanq_deq (dasd_chanq_t *, ccw_req_t *); +ccw_req_t *dasd_alloc_request (char *, int, int); +void dasd_free_request (ccw_req_t *); +int (*genhd_dasd_name) (char *, int, int, struct gendisk *); +int dasd_oper_handler (int irq, devreg_t * devreg); + +#endif /* __KERNEL__ */ + +#endif /* DASD_H */ + +/* + * Overrides for Emacs so that we follow Linus's tabbing style. + * Emacs will notice this stuff at the end of the file and automatically + * adjust the settings for this buffer only. This must remain at the end + * of the file. + * --------------------------------------------------------------------------- + * Local variables: + * c-indent-level: 4 + * c-brace-imaginary-offset: 0 + * c-brace-offset: -4 + * c-argdecl-indent: 4 + * c-label-offset: -4 + * c-continued-statement-offset: 4 + * c-continued-brace-offset: 0 + * indent-tabs-mode: nil + * tab-width: 8 + * End: + */ diff --git a/include/asm-s390/debug.h b/include/asm-s390/debug.h new file mode 100644 index 000000000..fdcc56008 --- /dev/null +++ b/include/asm-s390/debug.h @@ -0,0 +1,210 @@ +/* + * include/asm-s390/debug.h + * S/390 debug facility + * + * Copyright (C) 1999, 2000 IBM Deutschland Entwicklung GmbH, + * IBM Corporation + */ + +#ifndef DEBUG_H +#define DEBUG_H + +/* Note: + * struct __debug_entry must be defined outside of #ifdef __KERNEL__ + * in order to allow a user program to analyze the 'raw'-view. + */ + +struct __debug_entry{ + union { + struct { + unsigned long long clock:52; + unsigned long long exception:1; + unsigned long long used:1; + unsigned long long unused:1; + unsigned long long cpuid:9; + } fields; + + unsigned long long stck; + } id; + void* caller; +} __attribute__((packed)); + +#ifdef __KERNEL__ +#include <linux/version.h> +#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) + #include <asm/spinlock.h> +#else + #include <linux/spinlock.h> +#endif /* LINUX_VERSION_CODE */ +#include <linux/kernel.h> +#include <linux/time.h> +#include <linux/proc_fs.h> + +#define DEBUG_MAX_LEVEL 6 /* debug levels range from 0 to 6 */ +#define DEBUG_OFF_LEVEL -1 /* level where debug is switched off */ +#define DEBUG_MAX_VIEWS 10 /* max number of views in proc fs */ +#define DEBUG_MAX_PROCF_LEN 16 /* max length for a proc file name */ +#define DEBUG_DEFAULT_LEVEL 3 /* initial debug level */ +#define DEBUG_FEATURE_VERSION 1 /* version of debug feature */ + +#define DEBUG_DIR_ROOT "s390dbf" /* name of debug root directory in proc fs */ + +#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */ + /* the entry information */ + +#define STCK(x) asm volatile ("STCK %0":"=m" (x)) + +typedef struct __debug_entry debug_entry_t; + +struct debug_view; + +typedef struct debug_info { + struct debug_info* next; + struct debug_info* prev; + atomic_t ref_count; + spinlock_t lock; + int level; + int nr_areas; + int page_order; + int buf_size; + int entry_size; + debug_entry_t** areas; + int active_area; + int *active_entry; + struct proc_dir_entry* proc_root_entry; + struct proc_dir_entry* proc_entries[DEBUG_MAX_VIEWS]; + struct debug_view* views[DEBUG_MAX_VIEWS]; + char name[DEBUG_MAX_PROCF_LEN]; +} debug_info_t; + +typedef int (debug_header_proc_t) (debug_info_t* id, + struct debug_view* view, + int area, + debug_entry_t* entry, + char* out_buf); + +typedef int (debug_format_proc_t) (debug_info_t* id, + struct debug_view* view, char* out_buf, + const char* in_buf); +typedef int (debug_prolog_proc_t) (debug_info_t* id, + struct debug_view* view, + char* out_buf); +typedef int (debug_input_proc_t) (debug_info_t* id, + struct debug_view* view, + struct file* file, const char* user_buf, + size_t in_buf_size, loff_t* offset); + +int debug_dflt_header_fn(debug_info_t* id, struct debug_view* view, + int area, debug_entry_t* entry, char* out_buf); + +struct debug_view { + char name[DEBUG_MAX_PROCF_LEN]; + debug_prolog_proc_t* prolog_proc; + debug_header_proc_t* header_proc; + debug_format_proc_t* format_proc; + debug_input_proc_t* input_proc; +}; + +extern struct debug_view debug_hex_ascii_view; +extern struct debug_view debug_raw_view; + +debug_info_t* debug_register(char* name, int pages_index, int nr_areas, + int buf_size); +void debug_unregister(debug_info_t* id); + +void debug_set_level(debug_info_t* id, int new_level); + +debug_entry_t* debug_event(debug_info_t* id, int level, void* data, + int length); +debug_entry_t* debug_int_event(debug_info_t* id, int level, + unsigned int tag); +debug_entry_t* debug_text_event(debug_info_t* id, int level, + const char* txt); + +debug_entry_t* debug_exception(debug_info_t* id, int level, void* data, + int length); +debug_entry_t* debug_int_exception(debug_info_t* id, int level, + unsigned int tag); +debug_entry_t* debug_text_exception(debug_info_t* id, int level, + const char* txt); + +static inline debug_entry_t * +debug_long_event (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + return debug_event(id,level,&t,sizeof(unsigned long)); +} +static inline debug_entry_t * +debug_long_exception (debug_info_t* id, int level, unsigned long tag) +{ + unsigned long t=tag; + return debug_exception(id,level,&t,sizeof(unsigned long)); +} +int debug_register_view(debug_info_t* id, struct debug_view* view); +int debug_unregister_view(debug_info_t* id, struct debug_view* view); + +/* + define the debug levels: + - 0 No debugging output to console or syslog + - 1 Log internal errors to syslog, ignore check conditions + - 2 Log internal errors and check conditions to syslog + - 3 Log internal errors to console, log check conditions to syslog + - 4 Log internal errors and check conditions to console + - 5 panic on internal errors, log check conditions to console + - 6 panic on both, internal errors and check conditions + */ + +#ifndef DEBUG_LEVEL +#define DEBUG_LEVEL 4 +#endif + +#define INTERNAL_ERRMSG(x,y...) "E" __FILE__ "%d: " x, __LINE__, y +#define INTERNAL_WRNMSG(x,y...) "W" __FILE__ "%d: " x, __LINE__, y +#define INTERNAL_INFMSG(x,y...) "I" __FILE__ "%d: " x, __LINE__, y +#define INTERNAL_DEBMSG(x,y...) "D" __FILE__ "%d: " x, __LINE__, y + +#if DEBUG_LEVEL > 0 +#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#define PRINT_INFO(x...) printk ( KERN_INFO PRINTK_HEADER x ) +#define PRINT_WARN(x...) printk ( KERN_WARNING PRINTK_HEADER x ) +#define PRINT_ERR(x...) printk ( KERN_ERR PRINTK_HEADER x ) +#define PRINT_FATAL(x...) panic ( PRINTK_HEADER x ) +#else +#define PRINT_DEBUG(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#define PRINT_INFO(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#define PRINT_WARN(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#define PRINT_ERR(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#define PRINT_FATAL(x...) printk ( KERN_DEBUG PRINTK_HEADER x ) +#endif /* DASD_DEBUG */ + +#if DASD_DEBUG > 4 +#define INTERNAL_ERROR(x...) PRINT_FATAL ( INTERNAL_ERRMSG ( x ) ) +#elif DASD_DEBUG > 2 +#define INTERNAL_ERROR(x...) PRINT_ERR ( INTERNAL_ERRMSG ( x ) ) +#elif DASD_DEBUG > 0 +#define INTERNAL_ERROR(x...) PRINT_WARN ( INTERNAL_ERRMSG ( x ) ) +#else +#define INTERNAL_ERROR(x...) +#endif /* DASD_DEBUG */ + +#if DASD_DEBUG > 5 +#define INTERNAL_CHECK(x...) PRINT_FATAL ( INTERNAL_CHKMSG ( x ) ) +#elif DASD_DEBUG > 3 +#define INTERNAL_CHECK(x...) PRINT_ERR ( INTERNAL_CHKMSG ( x ) ) +#elif DASD_DEBUG > 1 +#define INTERNAL_CHECK(x...) PRINT_WARN ( INTERNAL_CHKMSG ( x ) ) +#else +#define INTERNAL_CHECK(x...) +#endif /* DASD_DEBUG */ + +#undef DEBUG_MALLOC +#ifdef DEBUG_MALLOC +void *b; +#define kmalloc(x...) (PRINT_INFO(" kmalloc %p\n",b=kmalloc(x)),b) +#define kfree(x) PRINT_INFO(" kfree %p\n",x);kfree(x) +#define get_free_page(x...) (PRINT_INFO(" gfp %p\n",b=get_free_page(x)),b) +#define __get_free_pages(x...) (PRINT_INFO(" gfps %p\n",b=__get_free_pages(x)),b) +#endif /* DEBUG_MALLOC */ + +#endif /* __KERNEL__ */ +#endif /* DEBUG_H */ diff --git a/include/asm-s390/delay.h b/include/asm-s390/delay.h index 87ac55391..357fdb835 100644 --- a/include/asm-s390/delay.h +++ b/include/asm-s390/delay.h @@ -15,11 +15,8 @@ #define _S390_DELAY_H extern void __udelay(unsigned long usecs); -extern void __const_udelay(unsigned long usecs); extern void __delay(unsigned long loops); -#define udelay(n) (__builtin_constant_p(n) ? \ - __const_udelay((n) * 0x10c6ul) : \ - __udelay(n)) +#define udelay(n) __udelay(n) #endif /* defined(_S390_DELAY_H) */ diff --git a/include/asm-s390/dma.h b/include/asm-s390/dma.h index e7ae126e6..e7e157330 100644 --- a/include/asm-s390/dma.h +++ b/include/asm-s390/dma.h @@ -1,5 +1,5 @@ /* - * include/asm-s390/delay.h + * include/asm-s390/dma.h * * S390 version * @@ -11,7 +11,6 @@ #include <asm/io.h> /* need byte IO */ -#define MAX_DMA_CHANNELS 0 #define MAX_DMA_ADDRESS 0x80000000 #endif /* _ASM_DMA_H */ diff --git a/include/asm-s390/ebcdic.h b/include/asm-s390/ebcdic.h index 7d6aeb2a7..be17f99d4 100644 --- a/include/asm-s390/ebcdic.h +++ b/include/asm-s390/ebcdic.h @@ -14,6 +14,8 @@ #include <types.h> #endif +extern __u8 _ascebc_500[]; /* ASCII -> EBCDIC 500 conversion table */ +extern __u8 _ebcasc_500[]; /* EBCDIC 500 -> ASCII conversion table */ extern __u8 _ascebc[]; /* ASCII -> EBCDIC conversion table */ extern __u8 _ebcasc[]; /* EBCDIC -> ASCII conversion table */ extern __u8 _ebc_tolower[]; /* EBCDIC -> lowercase */ @@ -44,6 +46,8 @@ void codepage_convert(const __u8 *codepage, volatile __u8 * addr, int nr) #define ASCEBC(addr,nr) codepage_convert(_ascebc, addr, nr) #define EBCASC(addr,nr) codepage_convert(_ebcasc, addr, nr) +#define ASCEBC_500(addr,nr) codepage_convert(_ascebc_500, addr, nr) +#define EBCASC_500(addr,nr) codepage_convert(_ebcasc_500, addr, nr) #define EBC_TOLOWER(addr,nr) codepage_convert(_ebc_tolower, addr, nr) #define EBC_TOUPPER(addr,nr) codepage_convert(_ebc_toupper, addr, nr) diff --git a/include/asm-s390/elf.h b/include/asm-s390/elf.h index 28c5e47db..1f4de7c51 100644 --- a/include/asm-s390/elf.h +++ b/include/asm-s390/elf.h @@ -19,10 +19,6 @@ typedef s390_fp_regs elf_fpregset_t; typedef s390_regs elf_gregset_t; -/* - * This is used to ensure we don't load something for the wrong architecture. - */ -#define elf_check_arch(x) ((x)->e_machine == EM_S390) /* * These are used to set parameters in the core dumps. @@ -31,6 +27,12 @@ typedef s390_regs elf_gregset_t; #define ELF_DATA ELFDATA2MSB #define ELF_ARCH EM_S390 +/* + * This is used to ensure we don't load something for the wrong architecture. + */ +#define elf_check_arch(x) \ + ((x)->e_machine == ELF_ARCH && (x)->e_ident[EI_CLASS] == ELF_CLASS) + /* For SVR4/S390 the function pointer to be registered with `atexit` is passed in R14. */ #define ELF_PLAT_INIT(_r) \ @@ -73,8 +75,7 @@ typedef s390_regs elf_gregset_t; #define ELF_PLATFORM (NULL) #ifdef __KERNEL__ -#define SET_PERSONALITY(ex, ibcs2) \ - current->personality = (ibcs2 ? PER_SVR4 : PER_LINUX) +#define SET_PERSONALITY(ex, ibcs2) set_personality((ibcs2)?PER_SVR4:PER_LINUX) #endif #endif diff --git a/include/asm-s390/fcntl.h b/include/asm-s390/fcntl.h index c1987889a..80fdd6c2e 100644 --- a/include/asm-s390/fcntl.h +++ b/include/asm-s390/fcntl.h @@ -42,6 +42,11 @@ #define F_SETSIG 10 /* for sockets. */ #define F_GETSIG 11 /* for sockets. */ +#define F_GETLK64 12 /* using 'struct flock64' */ +#define F_SETLK64 13 +#define F_SETLKW64 14 + + /* for F_[GET|SET]FL */ #define FD_CLOEXEC 1 /* actually anything with low bit set goes */ @@ -77,5 +82,13 @@ struct flock { pid_t l_pid; }; +struct flock64 { + short l_type; + short l_whence; + loff_t l_start; + loff_t l_len; + pid_t l_pid; +}; + #define F_LINUX_SPECIFIC_BASE 1024 #endif diff --git a/include/asm-s390/hardirq.h b/include/asm-s390/hardirq.h index b32a0684a..05a95993c 100644 --- a/include/asm-s390/hardirq.h +++ b/include/asm-s390/hardirq.h @@ -50,14 +50,14 @@ * Special definitions for s390, always access current PSA. */ #define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0) - + #define in_irq() (S390_lowcore.__local_irq_count != 0) - + #ifndef CONFIG_SMP - + #define hardirq_trylock(cpu) (local_irq_count(cpu) == 0) #define hardirq_endlock(cpu) do { } while (0) - + #define hardirq_enter(cpu) (local_irq_count(cpu)++) #define hardirq_exit(cpu) (local_irq_count(cpu)--) diff --git a/include/asm-s390/idals.h b/include/asm-s390/idals.h new file mode 100644 index 000000000..7d5232b65 --- /dev/null +++ b/include/asm-s390/idals.h @@ -0,0 +1,57 @@ +/* + * File...........: linux/include/asm-s390x/idals.h + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 2000a + + * History of changes + * 07/24/00 new file + */ +#include <linux/config.h> +#include <asm/irq.h> + +typedef unsigned long idaw_t; + +static inline idaw_t * +idal_alloc ( int nridaws ) +{ + if ( nridaws > 33 ) + BUG(); + return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA ); +} + +static inline void +idal_free ( idaw_t *idal ) +{ + kfree (idal); +} + +/* + * Function: set_normalized_cda + * sets the address of the data in CCW + * if necessary it allocates an IDAL and sets sthe appropriate flags + */ +#if defined (CONFIG_ARCH_S390X) +extern void set_normalized_cda(ccw1_t * ccw, unsigned long address); +#else +static inline void +set_normalized_cda(ccw1_t * ccw, unsigned long address) +{ + ccw->cda = address; +} +#endif + +/* + * Function: clear_normalized_cda + * releases any allocated IDAL related to the CCW + */ +static inline void +clear_normalized_cda ( ccw1_t * ccw ) +{ + if ( ccw -> flags & CCW_FLAG_IDA ) { + idal_free ( (idaw_t *) (ccw -> cda )); + ccw -> flags &= ~CCW_FLAG_IDA; + } + ccw -> cda = 0; +} + diff --git a/include/asm-s390/io.h b/include/asm-s390/io.h index 87c4edb72..11bd4217a 100644 --- a/include/asm-s390/io.h +++ b/include/asm-s390/io.h @@ -27,7 +27,7 @@ extern inline unsigned long virt_to_phys(volatile void * address) { unsigned long real_address; - __asm__ (" lra %0,0(0,%1)\n" + __asm__ (" lra %0,0(%1)\n" " jz 0f\n" " sr %0,%0\n" "0:" diff --git a/include/asm-s390/ioctls.h b/include/asm-s390/ioctls.h index 41748666a..db7b0a0c3 100644 --- a/include/asm-s390/ioctls.h +++ b/include/asm-s390/ioctls.h @@ -73,6 +73,7 @@ #define TIOCMIWAIT 0x545C /* wait for a change on serial input line(s) */ #define TIOCGICOUNT 0x545D /* read serial port inline interrupt counts */ +#define FIOQSIZE 0x545E /* Used for packet mode */ #define TIOCPKT_DATA 0 diff --git a/include/asm-s390/irq.h b/include/asm-s390/irq.h index 5efcdd40b..9849d6fdc 100644 --- a/include/asm-s390/irq.h +++ b/include/asm-s390/irq.h @@ -1,15 +1,8 @@ -/* - * arch/s390/kernel/s390io.h - * - * S390 version - * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Ingo Adlung (adlung@de.ibm.com) - */ - #ifndef __irq_h #define __irq_h #include <linux/config.h> +#ifdef __KERNEL__ #include <asm/hardirq.h> /* @@ -18,6 +11,8 @@ #define __MAX_SUBCHANNELS 65536 #define NR_IRQS __MAX_SUBCHANNELS +#define LPM_ANYPATH 0xff /* doesn't really belong here, Ingo? */ + #define INVALID_STORAGE_AREA ((void *)(-1 - 0x3FFF )) extern int disable_irq(unsigned int); @@ -50,7 +45,8 @@ struct hw_interrupt_type { */ typedef struct { __u32 intparm; /* interruption parameter */ - __u32 res0 : 2; /* reserved zeros */ + __u32 qf : 1; /* qdio facility */ + __u32 res0 : 1; /* reserved zeros */ __u32 isc : 3; /* interruption sublass */ __u32 res5 : 3; /* reserved zeros */ __u32 ena : 1; /* enabled */ @@ -77,6 +73,7 @@ typedef struct { /* ... in an operand exception. */ } __attribute__ ((packed)) pmcw_t; +#endif /* __KERNEL__ */ /* * subchannel status word */ @@ -89,7 +86,7 @@ typedef struct { __u32 pfch : 1; /* prefetch */ __u32 isic : 1; /* initial-status interruption control */ __u32 alcc : 1; /* address-limit checking control */ - __u32 ssi : 1; /* supress-suspended interruption */ + __u32 ssi : 1; /* suppress-suspended interruption */ __u32 zcc : 1; /* zero condition code */ __u32 ectl : 1; /* extended control */ __u32 pno : 1; /* path not operational */ @@ -140,6 +137,44 @@ typedef struct { #define SCHN_STAT_CHAIN_CHECK 0x01 /* + * architectured values for first sense byte + */ +#define SNS0_CMD_REJECT 0x80 +#define SNS_CMD_REJECT SNS0_CMD_REJECT +#define SNS0_INTERVENTION_REQ 0x40 +#define SNS0_BUS_OUT_CHECK 0x20 +#define SNS0_EQUIPMENT_CHECK 0x10 +#define SNS0_DATA_CHECK 0x08 +#define SNS0_OVERRUN 0x04 +/* 0x02 reserved */ +#define SNS0_INCOMPL_DOMAIN 0x01 + +/* + * architectured values for second sense byte + */ +#define SNS1_PERM_ERR 0x80 +#define SNS1_INV_TRACK_FORMAT 0x40 +#define SNS1_EOC 0x20 +#define SNS1_MESSAGE_TO_OPER 0x10 +#define SNS1_NO_REC_FOUND 0x08 +#define SNS1_FILE_PROTECTED 0x04 +#define SNS1_WRITE_INHIBITED 0x02 +#define SNS1_INPRECISE_END 0x01 + +/* + * architectured values for third sense byte + */ +#define SNS2_REQ_INH_WRITE 0x80 +#define SNS2_CORRECTABLE 0x40 +#define SNS2_FIRST_LOG_ERR 0x20 +#define SNS2_ENV_DATA_PRESENT 0x10 +/* 0x08 reserved */ +#define SNS2_INPRECISE_END 0x04 +/* 0x02 reserved */ +/* 0x01 reserved */ + +#ifdef __KERNEL__ +/* * subchannel information block */ typedef struct { @@ -147,13 +182,14 @@ typedef struct { scsw_t scsw; /* subchannel status word */ __u8 mda[12]; /* model dependent area */ } __attribute__ ((packed,aligned(4))) schib_t; +#endif /* __KERNEL__ */ typedef struct { __u8 cmd_code;/* command code */ - __u8 flags; /* flags, like IDA adressing, etc. */ + __u8 flags; /* flags, like IDA addressing, etc. */ __u16 count; /* byte count */ __u32 cda; /* data address */ - } ccw1_t __attribute__ ((packed,aligned(8))); + } __attribute__ ((packed,aligned(8))) ccw1_t; #define CCW_FLAG_DC 0x80 #define CCW_FLAG_CC 0x40 @@ -168,10 +204,13 @@ typedef struct { #define CCW_CMD_BASIC_SENSE 0x04 #define CCW_CMD_TIC 0x08 #define CCW_CMD_SENSE_PGID 0x34 +#define CCW_CMD_SUSPEND_RECONN 0x5B #define CCW_CMD_RDC 0x64 #define CCW_CMD_SET_PGID 0xAF #define CCW_CMD_SENSE_ID 0xE4 +#define CCW_CMD_DCTL 0xF3 +#ifdef __KERNEL__ #define SENSE_MAX_COUNT 0x20 /* @@ -192,19 +231,25 @@ typedef struct { __u32 intparm; /* interruption parameter */ __u32 key : 4; /* flags, like key, suspend control, etc. */ __u32 spnd : 1; /* suspend control */ - __u32 res1 : 3; /* reserved */ + __u32 res1 : 1; /* reserved */ + __u32 mod : 1; /* modification control */ + __u32 sync : 1; /* synchronize control */ __u32 fmt : 1; /* format control */ __u32 pfch : 1; /* prefetch control */ __u32 isic : 1; /* initial-status-interruption control */ __u32 alcc : 1; /* address-limit-checking control */ __u32 ssic : 1; /* suppress-suspended-interr. control */ - __u32 res2 : 3; /* reserved */ + __u32 res2 : 1; /* reserved */ + __u32 c64 : 1; /* IDAW/QDIO 64 bit control */ + __u32 i2k : 1; /* IDAW 2/4kB block size control */ __u32 lpm : 8; /* logical path mask */ __u32 ils : 1; /* incorrect length */ - __u32 zero : 7; /* reserved zeros */ + __u32 zero : 6; /* reserved zeros */ + __u32 orbx : 1; /* ORB extension control */ __u32 cpa; /* channel program address */ } __attribute__ ((packed,aligned(4))) orb_t; +#endif /* __KERNEL__ */ typedef struct { __u32 res0 : 4; /* reserved */ __u32 pvrf : 1; /* path-verification-required flag */ @@ -249,7 +294,7 @@ typedef struct { typedef struct { __u8 zero0; /* reserved zeros */ __u8 lpum; /* last path used mask */ - __u8 zero16; /* reserved zeros */ + __u16 zero16; /* reserved zeros */ erw_t erw; /* extended report word */ __u32 zeros[3]; /* 2 fullwords of zeros */ } __attribute__ ((packed)) esw1_t; @@ -291,30 +336,24 @@ typedef struct { esw_t esw; /* extended status word */ __u8 ecw[32]; /* extended control word */ } irb_t __attribute__ ((packed,aligned(4))); +#ifdef __KERNEL__ /* * TPI info structure */ typedef struct { - __u32 res : 16; /* reserved 0x00000001 */ - __u32 irq : 16; /* aka. subchannel number */ - __u32 intparm; /* interruption parameter */ + __u32 reserved1 : 16; /* reserved 0x00000001 */ + __u32 irq : 16; /* aka. subchannel number */ + __u32 intparm; /* interruption parameter */ + __u32 adapter_IO : 1; + __u32 reserved2 : 1; + __u32 isc : 3; + __u32 reserved3 : 12; + __u32 int_type : 3; + __u32 reserved4 : 12; } __attribute__ ((packed)) tpi_info_t; -/* - * This is the "IRQ descriptor", which contains various information - * about the irq, including what kind of hardware handling it has, - * whether it is disabled etc etc. - * - * Pad this out to 32 bytes for cache and indexing reasons. - */ -typedef struct { - __u32 status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ - struct hw_interrupt_type *handler; /* handle/enable/disable functions */ - struct irqaction *action; /* IRQ action list */ - } irq_desc_t; - // // command information word (CIW) layout // @@ -330,6 +369,7 @@ typedef struct _ciw { #define CIW_TYPE_SII 0x1 // set interface identifier #define CIW_TYPE_RNI 0x2 // read node identifier +#define MAX_CIWS 8 // // sense-id response buffer layout // @@ -342,9 +382,10 @@ typedef struct { __u8 dev_model; /* device model */ __u8 unused; /* padding byte */ /* extended part */ - ciw_t ciw[62]; /* variable # of CIWs */ + ciw_t ciw[MAX_CIWS]; /* variable # of CIWs */ } __attribute__ ((packed,aligned(4))) senseid_t; +#endif /* __KERNEL__ */ /* * sense data */ @@ -363,7 +404,7 @@ typedef struct { */ typedef struct { __u16 devno; /* device number, aka. "cuu" from irb */ - unsigned int intparm; /* interrupt parameter */ + unsigned long intparm; /* interrupt parameter */ __u8 cstat; /* channel status - accumulated */ __u8 dstat; /* device status - accumulated */ __u8 lpum; /* last path used mask from irb */ @@ -387,9 +428,53 @@ typedef struct { #define DEVSTAT_DEVICE_GONE 0x00000040 #define DEVSTAT_DEVICE_OWNED 0x00000080 #define DEVSTAT_CLEAR_FUNCTION 0x00000100 +#define DEVSTAT_PCI 0x00000200 +#define DEVSTAT_SUSPENDED 0x00000400 +#define DEVSTAT_UNKNOWN_DEV 0x00000800 #define DEVSTAT_FINAL_STATUS 0x80000000 +#define DEVINFO_NOT_OPER DEVSTAT_NOT_OPER +#define DEVINFO_UNKNOWN_DEV DEVSTAT_UNKNOWN_DEV +#define DEVINFO_DEVICE_OWNED DEVSTAT_DEVICE_OWNED +#define DEVINFO_QDIO_CAPABLE 0x40000000 + #define INTPARM_STATUS_PENDING 0xFFFFFFFF +#ifdef __KERNEL__ + +#define IO_INTERRUPT_TYPE 0 /* I/O interrupt type */ + +typedef void (* io_handler_func1_t) ( int irq, + devstat_t *devstat, + struct pt_regs *rgs); + +typedef void (* io_handler_func_t) ( int irq, + void *devstat, + struct pt_regs *rgs); + +typedef void ( * not_oper_handler_func_t)( int irq, + int status ); + +typedef int (* adapter_int_handler_t)( __u32 intparm ); + +struct s390_irqaction { + io_handler_func_t handler; + unsigned long flags; + const char *name; + devstat_t *dev_id; +}; + +/* + * This is the "IRQ descriptor", which contains various information + * about the irq, including what kind of hardware handling it has, + * whether it is disabled etc etc. + * + * Pad this out to 32 bytes for cache and indexing reasons. + */ +typedef struct { + unsigned int status; /* IRQ status - IRQ_INPROGRESS, IRQ_DISABLED */ + struct hw_interrupt_type *handler; /* handle/enable/disable functions */ + struct s390_irqaction *action; /* IRQ action list */ + } irq_desc_t; typedef struct { __u8 state1 : 2; /* path state value 1 */ @@ -409,36 +494,39 @@ typedef struct { __u32 tod_high; /* high word TOD clock */ } __attribute__ ((packed)) pgid_t; +#define SPID_FUNC_SINGLE_PATH 0x00 #define SPID_FUNC_MULTI_PATH 0x80 #define SPID_FUNC_ESTABLISH 0x00 #define SPID_FUNC_RESIGN 0x40 #define SPID_FUNC_DISBAND 0x20 -#define SNID_STATE1_RESET 0x0 -#define SNID_STATE1_UNGROUPED 0x8 -#define SNID_STATE1_GROUPED 0xC +#define SNID_STATE1_RESET 0 +#define SNID_STATE1_UNGROUPED 2 +#define SNID_STATE1_GROUPED 3 -#define SNID_STATE2_NOT_RESVD 0x0 -#define SNID_STATE2_RESVD_ELSE 0x8 -#define SNID_STATE2_RESVD_SELF 0xC +#define SNID_STATE2_NOT_RESVD 0 +#define SNID_STATE2_RESVD_ELSE 2 +#define SNID_STATE2_RESVD_SELF 3 #define SNID_STATE3_MULTI_PATH 1 +#define SNID_STATE3_SINGLE_PATH 0 /* * Flags used as input parameters for do_IO() */ -#define DOIO_EARLY_NOTIFICATION 0x01 /* allow for I/O completion ... */ +#define DOIO_EARLY_NOTIFICATION 0x0001 /* allow for I/O completion ... */ /* ... notification after ... */ /* ... primary interrupt status */ -#define DOIO_RETURN_CHAN_END DOIO_EARLY_NOTIFICATION -#define DOIO_VALID_LPM 0x02 /* LPM input parameter is valid */ -#define DOIO_WAIT_FOR_INTERRUPT 0x04 /* wait synchronously for interrupt */ -#define DOIO_REPORT_ALL 0x08 /* report all interrupt conditions */ -#define DOIO_ALLOW_SUSPEND 0x10 /* allow for channel prog. suspend */ -#define DOIO_DENY_PREFETCH 0x20 /* don't allow for CCW prefetch */ -#define DOIO_SUPPRESS_INTER 0x40 /* suppress intermediate inter. */ +#define DOIO_RETURN_CHAN_END DOIO_EARLY_NOTIFICATION +#define DOIO_VALID_LPM 0x0002 /* LPM input parameter is valid */ +#define DOIO_WAIT_FOR_INTERRUPT 0x0004 /* wait synchronously for interrupt */ +#define DOIO_REPORT_ALL 0x0008 /* report all interrupt conditions */ +#define DOIO_ALLOW_SUSPEND 0x0010 /* allow for channel prog. suspend */ +#define DOIO_DENY_PREFETCH 0x0020 /* don't allow for CCW prefetch */ +#define DOIO_SUPPRESS_INTER 0x0040 /* suppress intermediate inter. */ /* ... for suspended CCWs */ -#define DOIO_TIMEOUT 0x80 /* 3 secs. timeout for sync. I/O */ +#define DOIO_TIMEOUT 0x0080 /* 3 secs. timeout for sync. I/O */ +#define DOIO_DONT_CALL_INTHDLR 0x0100 /* don't call interrupt handler */ /* * do_IO() @@ -464,7 +552,7 @@ int do_IO( int irq, /* IRQ aka. subchannel number */ int start_IO( int irq, /* IRQ aka. subchannel number */ ccw1_t *cpa, /* logical channel program address */ - unsigned int intparm, /* interruption parameter */ + unsigned long intparm, /* interruption parameter */ __u8 lpm, /* logical path mask */ unsigned int flag); /* flags : see above */ @@ -493,12 +581,12 @@ typedef struct { __u16 devno; /* device number */ unsigned int status; /* device status */ senseid_t sid_data; /* senseID data */ - } dev_info_t; + } s390_dev_info_t; -int get_dev_info( int irq, dev_info_t *); /* to be eliminated - don't use */ +int get_dev_info( int irq, s390_dev_info_t *); /* to be eliminated - don't use */ -int get_dev_info_by_irq ( int irq, dev_info_t *pdi); -int get_dev_info_by_devno( __u16 devno, dev_info_t *pdi); +int get_dev_info_by_irq ( int irq, s390_dev_info_t *pdi); +int get_dev_info_by_devno( __u16 devno, s390_dev_info_t *pdi); int get_irq_by_devno( __u16 devno ); unsigned int get_devno_by_irq( int irq ); @@ -507,7 +595,16 @@ int get_irq_first( void ); int get_irq_next ( int irq ); int read_dev_chars( int irq, void **buffer, int length ); -int read_conf_data( int irq, void **buffer, int *length ); +int read_conf_data( int irq, void **buffer, int *length, __u8 lpm ); + +int s390_DevicePathVerification( int irq, __u8 domask ); + +int s390_request_irq_special( int irq, + io_handler_func_t io_handler, + not_oper_handler_func_t not_oper_handler, + unsigned long irqflags, + const char *devname, + void *dev_id); extern int handle_IRQ_event( unsigned int irq, int cpu, struct pt_regs *); @@ -524,7 +621,11 @@ extern __inline__ int stsch(int irq, volatile schib_t *addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "STSCH 0(%2)\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -538,7 +639,11 @@ extern __inline__ int msch(int irq, volatile schib_t *addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "MSCH 0(%2)\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -552,6 +657,21 @@ extern __inline__ int msch_err(int irq, volatile schib_t *addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + " lgr 1,%1\n" + " msch 0(%2)\n" + "0: ipm %0\n" + " srl %0,28\n" + "1:\n" + ".section .fixup,\"ax\"\n" + "2: l %0,%3\n" + " jg 1b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 8\n" + " .quad 0b,2b\n" + ".previous" +#else " lr 1,%1\n" " msch 0(%2)\n" "0: ipm %0\n" @@ -568,6 +688,7 @@ extern __inline__ int msch_err(int irq, volatile schib_t *addr) " .align 4\n" " .long 0b,2b\n" ".previous" +#endif : "=d" (ccode) : "r" (irq | 0x10000L), "a" (addr), "i" (__LC_PGM_ILC) : "cc", "1" ); @@ -579,7 +700,11 @@ extern __inline__ int tsch(int irq, volatile irb_t *addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "TSCH 0(%2)\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -606,7 +731,11 @@ extern __inline__ int ssch(int irq, volatile orb_t *addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "SSCH 0(%2)\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -620,7 +749,11 @@ extern __inline__ int rsch(int irq) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "RSCH\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -634,7 +767,11 @@ extern __inline__ int csch(int irq) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "CSCH\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -648,7 +785,11 @@ extern __inline__ int hsch(int irq) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else "LR 1,%1\n\t" +#endif "HSCH\n\t" "IPM %0\n\t" "SRL %0,28\n\t" @@ -669,6 +810,24 @@ extern __inline__ int iac( void) return ccode; } +extern __inline__ int rchp(int chpid) +{ + int ccode; + + __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "LGR 1,%1\n\t" +#else + "LR 1,%1\n\t" +#endif + "RCHP\n\t" + "IPM %0\n\t" + "SRL %0,28\n\t" + : "=d" (ccode) : "r" (chpid) + : "cc", "1" ); + return ccode; +} + typedef struct { __u16 vrdcdvno : 16; /* device number (input) */ __u16 vrdclen : 16; /* data block length (input) */ @@ -690,12 +849,18 @@ extern __inline__ int diag210( diag210_t * addr) int ccode; __asm__ __volatile__( +#ifdef CONFIG_ARCH_S390X + "SAM31\n\t" + "DIAG %1,0,0x210\n\t" + "SAM64\n\t" +#else "LR 1,%1\n\t" ".long 0x83110210\n\t" +#endif "IPM %0\n\t" "SRL %0,28\n\t" : "=d" (ccode) : "a" (addr) - : "cc", "1" ); + : "cc" ); return ccode; } @@ -720,9 +885,15 @@ extern spinlock_t irq_controller_lock; static inline void irq_enter(int cpu, unsigned int irq) { hardirq_enter(cpu); +#ifdef CONFIG_ARCH_S390X + while (atomic_read(&global_irq_lock) != 0) { + eieio(); + } +#else while (test_bit(0,&global_irq_lock)) { eieio(); } +#endif } static inline void irq_exit(int cpu, unsigned int irq) @@ -754,10 +925,13 @@ static inline void irq_exit(int cpu, unsigned int irq) * x86 profiling function, SMP safe. We might want to do this in * assembly totally? */ +extern char _stext; static inline void s390_do_profile (unsigned long addr) { -#if 0 if (prof_buffer && current->pid) { +#ifndef CONFIG_ARCH_S390X + addr &= 0x7fffffff; +#endif addr -= (unsigned long) &_stext; addr >>= prof_shift; /* @@ -769,7 +943,6 @@ static inline void s390_do_profile (unsigned long addr) addr = prof_len-1; atomic_inc((atomic_t *)&prof_buffer[addr]); } -#endif } #include <asm/s390io.h> @@ -784,5 +957,6 @@ static inline void s390_do_profile (unsigned long addr) spin_lock_irqsave(&(ioinfo[irq]->irq_lock), flags) #define s390irq_spin_unlock_irqrestore(irq,flags) \ spin_unlock_irqrestore(&(ioinfo[irq]->irq_lock), flags) +#endif /* __KERNEL__ */ #endif diff --git a/include/asm-s390/irqextras390.h b/include/asm-s390/irqextras390.h index 0ca2f718a..70bac7f44 100644 --- a/include/asm-s390/irqextras390.h +++ b/include/asm-s390/irqextras390.h @@ -100,7 +100,7 @@ typedef struct __u16 count; - void *ccw_data_address; + __u32 ccw_data_address; } ccw1_bits_t __attribute__((packed,aligned(8))); typedef struct diff --git a/include/asm-s390/lowcore.h b/include/asm-s390/lowcore.h index 3430056da..cdfa00fa2 100644 --- a/include/asm-s390/lowcore.h +++ b/include/asm-s390/lowcore.h @@ -31,10 +31,11 @@ #define __LC_SUBCHANNEL_ID 0x0B8 #define __LC_SUBCHANNEL_NR 0x0BA #define __LC_IO_INT_PARM 0x0BC +#define __LC_IO_INT_WORD 0x0C0 #define __LC_MCCK_CODE 0x0E8 -#define __LC_AREGS_SAVE_AREA 0x200 -#define __LC_CREGS_SAVE_AREA 0x240 -#define __LC_RETURN_PSW 0x280 +#define __LC_AREGS_SAVE_AREA 0x120 +#define __LC_CREGS_SAVE_AREA 0x1C0 +#define __LC_RETURN_PSW 0x200 #define __LC_SYNC_IO_WORD 0x400 @@ -45,7 +46,7 @@ #define __LC_CPUID 0xC60 #define __LC_CPUADDR 0xC68 #define __LC_IPLDEV 0xC7C - +#define __LC_PANIC_MAGIC 0xE00 /* interrupt handler start with all io, external and mcck interrupt disabled */ @@ -53,7 +54,7 @@ #define _EXT_PSW_MASK 0x04080000 #define _PGM_PSW_MASK 0x04080000 #define _SVC_PSW_MASK 0x04080000 -#define _MCCK_PSW_MASK 0x040A0000 +#define _MCCK_PSW_MASK 0x04080000 #define _IO_PSW_MASK 0x04080000 #define _USER_PSW_MASK 0x070DC000/* DAT, IO, EXT, Home-space */ #define _WAIT_PSW_MASK 0x070E0000/* DAT, IO, EXT, Wait, Home-space */ @@ -119,7 +120,8 @@ struct _lowcore __u16 subchannel_id; /* 0x0b8 */ __u16 subchannel_nr; /* 0x0ba */ __u32 io_int_parm; /* 0x0bc */ - __u8 pad3[0xD8-0xC0]; /* 0x0c0 */ + __u32 io_int_word; /* 0x0c0 */ + __u8 pad3[0xD8-0xC4]; /* 0x0c4 */ __u32 cpu_timer_save_area[2]; /* 0x0d8 */ __u32 clock_comp_save_area[2]; /* 0x0e0 */ __u32 mcck_interuption_code[2]; /* 0x0e8 */ @@ -128,15 +130,14 @@ struct _lowcore __u32 failing_storage_address; /* 0x0f8 */ __u8 pad5[0x100-0xfc]; /* 0x0fc */ __u32 st_status_fixed_logout[4];/* 0x100 */ - __u8 pad6[0x160-0x110]; /* 0x110 */ + __u8 pad6[0x120-0x110]; /* 0x110 */ + __u32 access_regs_save_area[16];/* 0x120 */ __u32 floating_pt_save_area[8]; /* 0x160 */ __u32 gpregs_save_area[16]; /* 0x180 */ - __u8 pad7[0x200-0x1c0]; /* 0x1c0 */ - - __u32 access_regs_save_area[16];/* 0x200 */ __u32 cregs_save_area[16]; /* 0x240 */ - psw_t return_psw; /* 0x280 */ - __u8 pad8[0x400-0x288]; /* 0x288 */ + + psw_t return_psw; /* 0x200 */ + __u8 pad8[0x400-0x208]; /* 0x208 */ __u32 sync_io_word; /* 0x400 */ @@ -163,9 +164,14 @@ struct _lowcore atomic_t ext_call_fast; /* 0xc88 */ atomic_t ext_call_queue; /* 0xc8c */ atomic_t ext_call_count; /* 0xc90 */ + __u8 pad11[0xe00-0xc94]; /* 0xc94 */ - /* Align SMP info to the top 1k of prefix area */ - __u8 pad11[0x1000-0xc94]; /* 0xc94 */ + /* 0xe00 is used as indicator for dump tools */ + /* whether the kernel died with panic() or not */ + __u32 panic_magic; /* 0xe00 */ + + /* Align to the top 1k of prefix area */ + __u8 pad12[0x1000-0xe04]; /* 0xe04 */ } __attribute__((packed)); /* End structure*/ extern __inline__ void set_prefix(__u32 address) @@ -186,5 +192,7 @@ extern struct _lowcore *lowcore_ptr[]; #endif #endif /* __ASSEMBLY__ */ +#define __PANIC_MAGIC 0xDEADC0DE + #endif diff --git a/include/asm-s390/mathemu.h b/include/asm-s390/mathemu.h index c78d97b43..429b3a4f4 100644 --- a/include/asm-s390/mathemu.h +++ b/include/asm-s390/mathemu.h @@ -12,12 +12,12 @@ extern int math_emu_b3(__u8 *, struct pt_regs *); extern int math_emu_ed(__u8 *, struct pt_regs *); -extern void math_emu_ldr(__u8 *); -extern void math_emu_ler(__u8 *); -extern void math_emu_std(__u8 *, struct pt_regs *); -extern void math_emu_ld(__u8 *, struct pt_regs *); -extern void math_emu_ste(__u8 *, struct pt_regs *); -extern void math_emu_le(__u8 *, struct pt_regs *); +extern int math_emu_ldr(__u8 *); +extern int math_emu_ler(__u8 *); +extern int math_emu_std(__u8 *, struct pt_regs *); +extern int math_emu_ld(__u8 *, struct pt_regs *); +extern int math_emu_ste(__u8 *, struct pt_regs *); +extern int math_emu_le(__u8 *, struct pt_regs *); extern int math_emu_lfpc(__u8 *, struct pt_regs *); extern int math_emu_stfpc(__u8 *, struct pt_regs *); extern int math_emu_srnm(__u8 *, struct pt_regs *); @@ -46,3 +46,6 @@ extern __u64 __extendsfdf2(__u32); #endif /* __MATHEMU__ */ + + + diff --git a/include/asm-s390/misc390.h b/include/asm-s390/misc390.h index 43d89ccfb..3a48a7385 100644 --- a/include/asm-s390/misc390.h +++ b/include/asm-s390/misc390.h @@ -12,3 +12,4 @@ #define allocaligned(type,name,number) allocaligned2(type,name,number,__alignof__(type)) +extern void s390_daemonize(char *name,unsigned long mask,int use_init_fs); diff --git a/include/asm-s390/mmu_context.h b/include/asm-s390/mmu_context.h index 71f0f66df..d58b14cbb 100644 --- a/include/asm-s390/mmu_context.h +++ b/include/asm-s390/mmu_context.h @@ -27,7 +27,8 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, unsigned long pgd; if (prev != next) { - pgd = (__pa(next->pgd) & PAGE_MASK) | _SEGMENT_TABLE; + pgd = (__pa(next->pgd)&PAGE_MASK) | + (_SEGMENT_TABLE|USER_STD_MASK); /* Load page tables */ asm volatile(" lctl 7,7,%0\n" /* secondary space */ " lctl 13,13,%0\n" /* home space */ diff --git a/include/asm-s390/namei.h b/include/asm-s390/namei.h index 524b93937..3e286bdde 100644 --- a/include/asm-s390/namei.h +++ b/include/asm-s390/namei.h @@ -16,7 +16,6 @@ * Look at asm-sparc/namei.h for details. */ -#define __prefix_lookup_dentry(name, lookup_flags) \ - do {} while (0) +#define __emul_prefix() NULL #endif /* __S390_NAMEI_H */ diff --git a/include/asm-s390/page.h b/include/asm-s390/page.h index e259b2bff..745db14f6 100644 --- a/include/asm-s390/page.h +++ b/include/asm-s390/page.h @@ -17,7 +17,15 @@ #ifdef __KERNEL__ #ifndef __ASSEMBLY__ -#define STRICT_MM_TYPECHECKS +/* + * gcc uses builtin, i.e. MVCLE for both operations + */ + +#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) +#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) + +#define clear_user_page(page, vaddr) clear_page(page) +#define copy_user_page(to, from, vaddr) copy_page(to, from) #define BUG() do { \ printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ @@ -43,14 +51,6 @@ extern __inline__ int get_order(unsigned long size) } /* - * gcc uses builtin, i.e. MVCLE for both operations - */ - -#define clear_page(page) memset((void *)(page), 0, PAGE_SIZE) -#define copy_page(to,from) memcpy((void *)(to), (void *)(from), PAGE_SIZE) - -#ifdef STRICT_MM_TYPECHECKS -/* * These are used to make use of C type-checking.. */ typedef struct { unsigned long pte; } pte_t; @@ -73,48 +73,18 @@ typedef struct { unsigned long pgprot; } pgprot_t; #define __pgd(x) ((pgd_t) { (x) } ) #define __pgprot(x) ((pgprot_t) { (x) } ) -#else -/* - * .. while these make it easier on the compiler - */ -typedef unsigned long pte_t; -typedef unsigned long pmd_t; -typedef struct { - unsigned long pgd0; - unsigned long pgd1; - unsigned long pgd2; - unsigned long pgd3; - } pgd_t; -typedef unsigned long pgprot_t; - -#define pte_val(x) (x) -#define pmd_val(x) (x) -#define pgd_val(x) (x) -#define pgprot_val(x) (x) - -#define __pte(x) (x) -#define __pmd(x) (x) -#define __pgd(x) (x) -#define __pgprot(x) (x) - -#endif -#endif /* !__ASSEMBLY__ */ +#endif /* !__ASSEMBLY__ */ /* to align the pointer to the (next) page boundary */ #define PAGE_ALIGN(addr) (((addr)+PAGE_SIZE-1)&PAGE_MASK) -/* - * - * - */ - -#define __PAGE_OFFSET (0x0) -#define PAGE_OFFSET ((unsigned long)__PAGE_OFFSET) -#define __pa(x) ((unsigned long)(x)-PAGE_OFFSET) -#define __va(x) ((void *)((unsigned long)(x)+PAGE_OFFSET)) +#define __PAGE_OFFSET 0x0UL +#define PAGE_OFFSET 0x0UL +#define __pa(x) (unsigned long)(x) +#define __va(x) (void *)(x) #define virt_to_page(kaddr) (mem_map + (__pa(kaddr) >> PAGE_SHIFT)) #define VALID_PAGE(page) ((page - mem_map) < max_mapnr) -#endif /* __KERNEL__ */ +#endif /* __KERNEL__ */ -#endif /* _S390_PAGE_H */ +#endif /* _S390_PAGE_H */ diff --git a/include/asm-s390/param.h b/include/asm-s390/param.h index bd04cebde..c6d7f934f 100644 --- a/include/asm-s390/param.h +++ b/include/asm-s390/param.h @@ -28,4 +28,8 @@ #define MAXHOSTNAMELEN 64 /* max length of hostname */ +#ifdef __KERNEL__ +# define CLOCKS_PER_SEC HZ /* frequency at which times() counts */ +#endif + #endif diff --git a/include/asm-s390/pgalloc.h b/include/asm-s390/pgalloc.h index c1fed9346..72c67617e 100644 --- a/include/asm-s390/pgalloc.h +++ b/include/asm-s390/pgalloc.h @@ -31,7 +31,7 @@ extern __inline__ pgd_t* get_pgd_slow(void) { int i; - pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,2); + pgd_t *pgd,*ret = (pgd_t *)__get_free_pages(GFP_KERNEL,1); if (ret) for (i=0,pgd=ret;i<USER_PTRS_PER_PGD;i++,pgd++) pmd_clear(pmd_offset(pgd,i*PGDIR_SIZE)); @@ -40,47 +40,80 @@ extern __inline__ pgd_t* get_pgd_slow(void) extern __inline__ pgd_t* get_pgd_fast(void) { - unsigned long *ret; + unsigned long *ret = pgd_quicklist; - if((ret = pgd_quicklist) != NULL) { + if (ret != NULL) { pgd_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; - pgtable_cache_size--; - /* - * Need to flush tlb, since private page tables - * are unique thru address of pgd and virtual address. - * If we reuse pgd we need to be sure no tlb entry - * with that pdg is left -> global flush - * - * Fixme: To avoid this global flush we should - * use pdg_quicklist as fix lenght fifo list - * and not as stack - */ - } else - ret = (unsigned long *)get_pgd_slow(); + pgtable_cache_size -= 2; + } return (pgd_t *)ret; } +extern __inline__ pgd_t *pgd_alloc(void) +{ + pgd_t *pgd; + + pgd = get_pgd_fast(); + if (!pgd) + pgd = get_pgd_slow(); + return pgd; +} + extern __inline__ void free_pgd_fast(pgd_t *pgd) { *(unsigned long *)pgd = (unsigned long) pgd_quicklist; pgd_quicklist = (unsigned long *) pgd; - pgtable_cache_size++; + pgtable_cache_size += 2; } extern __inline__ void free_pgd_slow(pgd_t *pgd) { - free_pages((unsigned long)pgd,2); + free_pages((unsigned long) pgd, 1); +} + +#define pgd_free(pgd) free_pgd_fast(pgd) + +/* + * page middle directory allocation/free routines. + * We don't use pmd cache, so these are dummy routines. + */ +extern __inline__ pmd_t *get_pmd_fast(void) +{ + return (pmd_t *)0; +} + +extern __inline__ void free_pmd_fast(pmd_t *pmd) +{ +} + +extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) +{ + return (pmd_t *) pgd; +} + +extern __inline__ void free_pmd_slow(pmd_t *pmd) +{ +} + +extern inline void pmd_free(pmd_t * pmd) +{ } +#define pmd_free_kernel pmd_free +#define pmd_alloc_kernel pmd_alloc + +/* + * page table entry allocation/free routines. + */ +extern pte_t empty_bad_pte_table[]; extern pte_t *get_pte_slow(pmd_t *pmd, unsigned long address_preadjusted); -extern pte_t *get_pte_kernel_slow(pmd_t *pmd, unsigned long address_preadjusted); extern __inline__ pte_t* get_pte_fast(void) { - unsigned long *ret; + unsigned long *ret = (unsigned long *) pte_quicklist; - if((ret = (unsigned long *)pte_quicklist) != NULL) { + if (ret != NULL) { pte_quicklist = (unsigned long *)(*ret); ret[0] = ret[1]; pgtable_cache_size--; @@ -90,6 +123,8 @@ extern __inline__ pte_t* get_pte_fast(void) extern __inline__ void free_pte_fast(pte_t *pte) { + if (pte == empty_bad_pte_table) + return; *(unsigned long *)pte = (unsigned long) pte_quicklist; pte_quicklist = (unsigned long *) pte; pgtable_cache_size++; @@ -97,79 +132,41 @@ extern __inline__ void free_pte_fast(pte_t *pte) extern __inline__ void free_pte_slow(pte_t *pte) { - free_page((unsigned long)pte); -} - -#define pte_free_kernel(pte) free_pte_fast(pte) -#define pte_free(pte) free_pte_fast(pte) -#define pgd_free(pgd) free_pgd_fast(pgd) -#define pgd_alloc() get_pgd_fast() - -extern inline pte_t * pte_alloc_kernel(pmd_t * pmd, unsigned long address) -{ - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); - if (pmd_none(*pmd)) { - pte_t * page = (pte_t *) get_pte_fast(); - - if (!page) - return get_pte_kernel_slow(pmd, address); - pmd_val(pmd[0]) = _KERNPG_TABLE + __pa(page); - pmd_val(pmd[1]) = _KERNPG_TABLE + __pa(page+1024); - pmd_val(pmd[2]) = _KERNPG_TABLE + __pa(page+2048); - pmd_val(pmd[3]) = _KERNPG_TABLE + __pa(page+3072); - return page + address; - } - if (pmd_bad(*pmd)) { - __handle_bad_pmd_kernel(pmd); - return NULL; - } - return (pte_t *) pmd_page(*pmd) + address; + free_page((unsigned long) pte); } -extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long address) +extern inline pte_t * pte_alloc(pmd_t * pmd, unsigned long vmaddr) { - address = (address >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + unsigned long offset; - if (pmd_none(*pmd)) - goto getnew; + offset = (vmaddr >> PAGE_SHIFT) & (PTRS_PER_PTE - 1); + if (pmd_none(*pmd)) { + unsigned long page = (unsigned long) get_pte_fast(); + + if (!page) + return get_pte_slow(pmd, offset); + pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page); + pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024); + pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048); + pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072); + return (pte_t *) page + offset; + } if (pmd_bad(*pmd)) - goto fix; - return (pte_t *) pmd_page(*pmd) + address; -getnew: -{ - unsigned long page = (unsigned long) get_pte_fast(); - - if (!page) - return get_pte_slow(pmd, address); - pmd_val(pmd[0]) = _PAGE_TABLE + __pa(page); - pmd_val(pmd[1]) = _PAGE_TABLE + __pa(page+1024); - pmd_val(pmd[2]) = _PAGE_TABLE + __pa(page+2048); - pmd_val(pmd[3]) = _PAGE_TABLE + __pa(page+3072); - return (pte_t *) page + address; -} -fix: - __handle_bad_pmd(pmd); - return NULL; -} - -/* - * allocating and freeing a pmd is trivial: the 1-entry pmd is - * inside the pgd, so has no extra memory associated with it. - */ -extern inline void pmd_free(pmd_t * pmd) -{ + BUG(); + return (pte_t *) pmd_page(*pmd) + offset; } -extern inline pmd_t * pmd_alloc(pgd_t * pgd, unsigned long address) -{ - return (pmd_t *) pgd; -} - -#define pmd_free_kernel pmd_free -#define pmd_alloc_kernel pmd_alloc +#define pte_alloc_kernel(pmd, addr) pte_alloc(pmd, addr) +#define pte_free_kernel(pte) free_pte_fast(pte) +#define pte_free(pte) free_pte_fast(pte) extern int do_check_pgt_cache(int, int); +/* + * This establishes kernel virtual mappings (e.g., as a result of a + * vmalloc call). Since s390-esame uses a separate kernel page table, + * there is nothing to do here... :) + */ #define set_pgdir(addr,entry) do { } while(0) /* @@ -185,161 +182,122 @@ extern int do_check_pgt_cache(int, int); */ /* - * s390 has two ways of flushing TLBs + * S/390 has three ways of flushing TLBs * 'ptlb' does a flush of the local processor - * 'ipte' invalidates a pte in a page table and flushes that out of - * the TLBs of all PUs of a SMP + * 'csp' flushes the TLBs on all PUs of a SMP + * 'ipte' invalidates a pte in a page table and flushes that out of + * the TLBs of all PUs of a SMP */ -#define __flush_tlb() \ +#define local_flush_tlb() \ do { __asm__ __volatile__("ptlb": : :"memory"); } while (0) -static inline void __flush_global_tlb(void) -{ - int cs1=0,dum=0; - int *adr; - long long dummy=0; - adr = (int*) (((int)(((int*) &dummy)+1) & 0xfffffffc)|1); - __asm__ __volatile__("lr 2,%0\n\t" - "lr 3,%1\n\t" - "lr 4,%2\n\t" - ".long 0xb2500024" : - : "d" (cs1), "d" (dum), "d" (adr) - : "2", "3", "4"); -} - -#if 0 -#define flush_tlb_one(a,b) __flush_tlb() -#define __flush_tlb_one(a,b) __flush_tlb() -#else -static inline void __flush_tlb_one(struct mm_struct *mm, - unsigned long addr) -{ - pgd_t * pgdir; - pmd_t * pmd; - pte_t * pte, *pto; - - pgdir = pgd_offset(mm, addr); - if (pgd_none(*pgdir) || pgd_bad(*pgdir)) - return; - pmd = pmd_offset(pgdir, addr); - if (pmd_none(*pmd) || pmd_bad(*pmd)) - return; - pte = pte_offset(pmd,addr); - - /* - * S390 has 1mb segments, we are emulating 4MB segments - */ - - pto = (pte_t*) (((unsigned long) pte) & 0x7ffffc00); - - __asm__ __volatile(" ic 0,2(%0)\n" - " ipte %1,%2\n" - " stc 0,2(%0)" - : : "a" (pte), "a" (pto), "a" (addr): "0"); -} -#endif - - #ifndef CONFIG_SMP -#define flush_tlb() __flush_tlb() -#define flush_tlb_all() __flush_tlb() -#define local_flush_tlb() __flush_tlb() - /* * We always need to flush, since s390 does not flush tlb * on each context switch */ +#define flush_tlb() local_flush_tlb() +#define flush_tlb_all() local_flush_tlb() +#define flush_tlb_mm(mm) local_flush_tlb() +#define flush_tlb_page(vma, va) local_flush_tlb() +#define flush_tlb_range(mm, start, end) local_flush_tlb() -static inline void flush_tlb_mm(struct mm_struct *mm) -{ - __flush_tlb(); -} +#else + +#include <asm/smp.h> -static inline void flush_tlb_page(struct vm_area_struct *vma, - unsigned long addr) +extern void smp_ptlb_all(void); +static inline void global_flush_tlb_csp(void) { - __flush_tlb_one(vma->vm_mm,addr); + int cs1=0,dum=0; + int *adr; + long long dummy=0; + adr = (int*) (((int)(((int*) &dummy)+1) & 0xfffffffc)|1); + __asm__ __volatile__("lr 2,%0\n\t" + "lr 3,%1\n\t" + "lr 4,%2\n\t" + "csp 2,4" : + : "d" (cs1), "d" (dum), "d" (adr) + : "2", "3", "4"); } - -static inline void flush_tlb_range(struct mm_struct *mm, - unsigned long start, unsigned long end) +static inline void global_flush_tlb(void) { - __flush_tlb(); + if (MACHINE_HAS_CSP) + global_flush_tlb_csp(); + else + smp_ptlb_all(); } -#else - -/* - * We aren't very clever about this yet - SMP could certainly - * avoid some global flushes.. - */ - -#include <asm/smp.h> - -#define local_flush_tlb() \ - __flush_tlb() - /* - * We only have to do global flush of tlb if process run since last - * flush on any other pu than current. - * If we have threads (mm->count > 1) we always do a global flush, - * since the process runs on more than one processor at the same time. + * We only have to do global flush of tlb if process run since last + * flush on any other pu than current. + * If we have threads (mm->count > 1) we always do a global flush, + * since the process runs on more than one processor at the same time. */ -static inline void flush_tlb_current_task(void) +static inline void __flush_tlb_mm(struct mm_struct * mm) { - if ((atomic_read(¤t->mm->mm_count) != 1) || - (current->mm->cpu_vm_mask != (1UL << smp_processor_id()))) { - current->mm->cpu_vm_mask = (1UL << smp_processor_id()); - __flush_global_tlb(); + if ((smp_num_cpus > 1) && + ((atomic_read(&mm->mm_count) != 1) || + (mm->cpu_vm_mask != (1UL << smp_processor_id())))) { + mm->cpu_vm_mask = (1UL << smp_processor_id()); + global_flush_tlb(); } else { local_flush_tlb(); } } -#define flush_tlb() flush_tlb_current_task() +#define flush_tlb() __flush_tlb_mm(current->mm) +#define flush_tlb_all() global_flush_tlb() +#define flush_tlb_mm(mm) __flush_tlb_mm(mm) +#define flush_tlb_page(vma, va) __flush_tlb_mm((vma)->vm_mm) +#define flush_tlb_range(mm, start, end) __flush_tlb_mm(mm) -#define flush_tlb_all() __flush_global_tlb() +#endif -static inline void flush_tlb_mm(struct mm_struct * mm) +extern inline void flush_tlb_pgtables(struct mm_struct *mm, + unsigned long start, unsigned long end) { - if ((atomic_read(&mm->mm_count) != 1) || - (mm->cpu_vm_mask != (1UL << smp_processor_id()))) { - mm->cpu_vm_mask = (1UL << smp_processor_id()); - __flush_global_tlb(); - } else { - local_flush_tlb(); - } + /* S/390 does not keep any page table caches in TLB */ } -static inline void flush_tlb_page(struct vm_area_struct * vma, - unsigned long va) + +static inline int ptep_test_and_clear_and_flush_young(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) { - __flush_tlb_one(vma->vm_mm,va); + /* No need to flush TLB; bits are in storage key */ + return ptep_test_and_clear_young(ptep); } -static inline void flush_tlb_range(struct mm_struct * mm, - unsigned long start, unsigned long end) +static inline int ptep_test_and_clear_and_flush_dirty(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) { - if ((atomic_read(&mm->mm_count) != 1) || - (mm->cpu_vm_mask != (1UL << smp_processor_id()))) { - mm->cpu_vm_mask = (1UL << smp_processor_id()); - __flush_global_tlb(); - } else { - local_flush_tlb(); - } + /* No need to flush TLB; bits are in storage key */ + return ptep_test_and_clear_dirty(ptep); } -#endif +static inline pte_t ptep_invalidate(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep) +{ + pte_t pte = *ptep; + if (!(pte_val(pte) & _PAGE_INVALID)) { + /* S390 has 1mb segments, we are emulating 4MB segments */ + pte_t *pto = (pte_t *) (((unsigned long) ptep) & 0x7ffffc00); + __asm__ __volatile__ ("ipte %0,%1" : : "a" (pto), "a" (address)); + } + pte_clear(ptep); + return pte; +} -extern inline void flush_tlb_pgtables(struct mm_struct *mm, - unsigned long start, unsigned long end) +static inline void ptep_establish(struct vm_area_struct *vma, + unsigned long address, pte_t *ptep, pte_t entry) { - /* S/390 does not keep any page table caches in TLB */ + ptep_invalidate(vma, address, ptep); + set_pte(ptep, entry); } #endif /* _S390_PGALLOC_H */ diff --git a/include/asm-s390/pgtable.h b/include/asm-s390/pgtable.h index 6906a875a..3c83ec404 100644 --- a/include/asm-s390/pgtable.h +++ b/include/asm-s390/pgtable.h @@ -3,7 +3,9 @@ * * S390 version * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation - * Author(s): Hartmut Penner + * Author(s): Hartmut Penner (hp@de.ibm.com) + * Ulrich Weigand (weigand@de.ibm.com) + * Martin Schwidefsky (schwidefsky@de.ibm.com) * * Derived from "include/asm-i386/pgtable.h" */ @@ -17,14 +19,19 @@ * table, so that we physically have the same two-level page table as the * S390 mmu expects. * + * The "pgd_xxx()" functions are trivial for a folded two-level + * setup: the pgd is never bad, and a pmd always exists (as it's folded + * into the pgd entry) + * * This file contains the functions and defines necessary to modify and use * the S390 page table tree. */ #ifndef __ASSEMBLY__ #include <asm/processor.h> -#include <linux/tasks.h> +#include <linux/threads.h> extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); +extern void paging_init(void); /* Caches aren't brain-dead on S390. */ #define flush_cache_all() do { } while (0) @@ -37,20 +44,30 @@ extern pgd_t swapper_pg_dir[] __attribute__ ((aligned (4096))); #define flush_icache_page(vma,pg) do { } while (0) /* + * The S390 doesn't have any external MMU info: the kernel page + * tables contain all the necessary information. + */ +#define update_mmu_cache(vma, address, pte) do { } while (0) + +/* * ZERO_PAGE is a global shared page that is always zero: used * for zero-mapped memory areas etc.. */ -extern unsigned long empty_zero_page[1024]; +extern char empty_zero_page[PAGE_SIZE]; #define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page)) #endif /* !__ASSEMBLY__ */ -/* Certain architectures need to do special things when PTEs +/* + * Certain architectures need to do special things when PTEs * within a page table are directly modified. Thus, the following * hook is made available. */ #define set_pte(pteptr, pteval) ((*(pteptr)) = (pteval)) -/* PMD_SHIFT determines the size of the area a second-level page table can map */ +/* + * PMD_SHIFT determines the size of the area a second-level page + * table can map + */ #define PMD_SHIFT 22 #define PMD_SIZE (1UL << PMD_SHIFT) #define PMD_MASK (~(PMD_SIZE-1)) @@ -70,7 +87,6 @@ extern unsigned long empty_zero_page[1024]; #define PTRS_PER_PMD 1 #define PTRS_PER_PGD 512 - /* * pgd entries used up by user/kernel: */ @@ -87,7 +103,8 @@ extern unsigned long empty_zero_page[1024]; printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) #ifndef __ASSEMBLY__ -/* Just any arbitrary offset to the start of the vmalloc VM area: the +/* + * Just any arbitrary offset to the start of the vmalloc VM area: the * current 8MB value just means that there will be a 8MB "hole" after the * physical memory until the kernel virtual memory starts. That means that * any out-of-bounds memory accesses will hopefully be caught. @@ -95,14 +112,14 @@ extern unsigned long empty_zero_page[1024]; * area for the same reason. ;) */ #define VMALLOC_OFFSET (8*1024*1024) -#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) +#define VMALLOC_START (((unsigned long) high_memory + VMALLOC_OFFSET) \ + & ~(VMALLOC_OFFSET-1)) #define VMALLOC_VMADDR(x) ((unsigned long)(x)) #define VMALLOC_END (0x7fffffffL) /* * A pagetable entry of S390 has following format: - * * | PFRA | | OS | * 0 0IP0 * 00000000001111111111222222222233 @@ -110,11 +127,8 @@ extern unsigned long empty_zero_page[1024]; * * I Page-Invalid Bit: Page is not available for address-translation * P Page-Protection Bit: Store access not possible for page - */ - -/* - * A segmenttable entry of S390 has following format: * + * A segmenttable entry of S390 has following format: * | P-table origin | |PTL * 0 IC * 00000000001111111111222222222233 @@ -122,10 +136,8 @@ extern unsigned long empty_zero_page[1024]; * * I Segment-Invalid Bit: Segment is not available for address-translation * C Common-Segment Bit: Segment is not private (PoP 3-30) - * PTL Page-Table-Length: Length of Page-table (PTL+1*16 entries -> up to 256 entries) - */ - -/* + * PTL Page-Table-Length: Page-table length (PTL+1*16 entries -> up to 256) + * * The segmenttable origin of S390 has following format: * * |S-table origin | | STL | @@ -137,27 +149,38 @@ extern unsigned long empty_zero_page[1024]; * G Segment-Invalid Bit: * * P Private-Space Bit: Segment is not private (PoP 3-30) * S Storage-Alteration: - * STL Segment-Table-Length: Length of Page-table (STL+1*16 entries -> up to 2048 entries) + * STL Segment-Table-Length: Segment-table length (STL+1*16 entries -> up to 2048) + * + * A storage key has the following format: + * | ACC |F|R|C|0| + * 0 3 4 5 6 7 + * ACC: access key + * F : fetch protection bit + * R : referenced bit + * C : changed bit */ +/* Bits in the page table entry */ #define _PAGE_PRESENT 0x001 /* Software */ -#define _PAGE_ACCESSED 0x002 /* Software accessed */ -#define _PAGE_DIRTY 0x004 /* Software dirty */ #define _PAGE_RO 0x200 /* HW read-only */ #define _PAGE_INVALID 0x400 /* HW invalid */ +/* Bits in the segment table entry */ #define _PAGE_TABLE_LEN 0xf /* only full page-tables */ #define _PAGE_TABLE_COM 0x10 /* common page-table */ #define _PAGE_TABLE_INV 0x20 /* invalid page-table */ #define _SEG_PRESENT 0x001 /* Software (overlap with PTL) */ +/* Bits int the storage key */ +#define _PAGE_CHANGED 0x02 /* HW changed bit */ +#define _PAGE_REFERENCED 0x04 /* HW referenced bit */ + #define _USER_SEG_TABLE_LEN 0x7f /* user-segment-table up to 2 GB */ #define _KERNEL_SEG_TABLE_LEN 0x7f /* kernel-segment-table up to 2 GB */ /* * User and Kernel pagetables are identical */ - #define _PAGE_TABLE (_PAGE_TABLE_LEN ) #define _KERNPG_TABLE (_PAGE_TABLE_LEN ) @@ -165,22 +188,25 @@ extern unsigned long empty_zero_page[1024]; * The Kernel segment-tables includes the User segment-table */ -#define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000) +#define _SEGMENT_TABLE (_USER_SEG_TABLE_LEN|0x80000000|0x100) #define _KERNSEG_TABLE (_KERNEL_SEG_TABLE_LEN) + /* * No mapping available */ -#define PAGE_NONE __pgprot(_PAGE_INVALID ) - -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_RO) -#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED | _PAGE_DIRTY) +#define PAGE_INVALID __pgprot(_PAGE_INVALID) +#define PAGE_NONE __pgprot(_PAGE_PRESENT | _PAGE_INVALID) +#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_RO) +#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_RO) +#define PAGE_SHARED __pgprot(_PAGE_PRESENT) +#define PAGE_KERNEL __pgprot(_PAGE_PRESENT) /* - * The S390 can't do page protection for execute, and considers that the same are read. - * Also, write permissions imply read permissions. This is the closest we can get.. + * The S390 can't do page protection for execute, and considers that the + * same are read. Also, write permissions imply read permissions. This is + * the closest we can get.. */ + /*xwr*/ #define __P000 PAGE_NONE #define __P001 PAGE_READONLY #define __P010 PAGE_COPY @@ -200,152 +226,199 @@ extern unsigned long empty_zero_page[1024]; #define __S111 PAGE_SHARED /* - * Define this if things work differently on an i386 and an i486: - * it will (on an i486) warn about kernel memory accesses that are - * done without a 'verify_area(VERIFY_WRITE,..)' - * - * Kernel and User memory-access are done equal, so we don't need verify + * Permanent address of a page. */ -#undef TEST_VERIFY_AREA +#define page_address(page) ((page)->virtual) +#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) -/* page table for 0-4MB for everybody */ -extern unsigned long pg0[1024]; +/* + * pgd/pmd/pte query functions + */ +extern inline int pgd_present(pgd_t pgd) { return 1; } +extern inline int pgd_none(pgd_t pgd) { return 0; } +extern inline int pgd_bad(pgd_t pgd) { return 0; } -/* number of bits that fit into a memory pointer */ -#define BITS_PER_PTR (8*sizeof(unsigned long)) +extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; } +extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PAGE_TABLE_INV; } +extern inline int pmd_bad(pmd_t pmd) +{ + return (pmd_val(pmd) & (~PAGE_MASK & ~_PAGE_TABLE_INV)) != _PAGE_TABLE; +} -/* to align the pointer to a pointer address */ -#define PTR_MASK (~(sizeof(void*)-1)) +extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } +extern inline int pte_none(pte_t pte) +{ + return ((pte_val(pte) & + (_PAGE_INVALID | _PAGE_RO | _PAGE_PRESENT)) == _PAGE_INVALID); +} -/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */ -/* 64-bit machines, beware! SRB. */ -#define SIZEOF_PTR_LOG2 2 +#define pte_same(a,b) (pte_val(a) == pte_val(b)) -/* to find an entry in a page-table */ -#define PAGE_PTR(address) \ -((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) +/* + * query functions pte_write/pte_dirty/pte_young only work if + * pte_present() is true. Undefined behaviour if not.. + */ +extern inline int pte_write(pte_t pte) +{ + return (pte_val(pte) & _PAGE_RO) == 0; +} +extern inline int pte_dirty(pte_t pte) +{ + int skey; + asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte))); + return skey & _PAGE_CHANGED; +} -/* - * CR 7 (SPST) and cr 13 (HPST) are set to the user pgdir. - * Kernel is running in its own, disjunct address space, - * running in primary address space. - * Copy to/from user is done via access register mode with - * access registers set to 0 or 1. For that purpose we need - * set up CR 7 with the user pgd. - * - */ +extern inline int pte_young(pte_t pte) +{ + int skey; -#define SET_PAGE_DIR(tsk,pgdir) \ -do { \ - unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \ - (tsk)->thread.user_seg = __pgdir; \ - if ((tsk) == current) { \ - __asm__ __volatile__("lctl 7,7,%0": :"m" (__pgdir)); \ - __asm__ __volatile__("lctl 13,13,%0": :"m" (__pgdir)); \ - } \ -} while (0) - -/* - * CR 7 (SPST) and cr 13 (HPST) are set to the user pgdir. - * Kernel is running in its own, disjunct address space, - * running in primary address space. - * Copy to/from user is done via access register mode with - * access registers set to 0 or 1. For that purpose we need - * set up CR 7 with the user pgd. - * + asm volatile ("iske %0,%1" : "=d" (skey) : "a" (pte_val(pte))); + return skey & _PAGE_REFERENCED; +} + +/* + * pgd/pmd/pte modification functions */ +extern inline void pgd_clear(pgd_t * pgdp) { } -#define SET_PAGE_DIR(tsk,pgdir) \ -do { \ - unsigned long __pgdir = (__pa(pgdir) & PAGE_MASK ) | _SEGMENT_TABLE; \ - (tsk)->thread.user_seg = __pgdir; \ - if ((tsk) == current) { \ - __asm__ __volatile__("lctl 7,7,%0": :"m" (__pgdir)); \ - __asm__ __volatile__("lctl 13,13,%0": :"m" (__pgdir)); \ - } \ -} while (0) +extern inline void pmd_clear(pmd_t * pmdp) +{ + pmd_val(pmdp[0]) = _PAGE_TABLE_INV; + pmd_val(pmdp[1]) = _PAGE_TABLE_INV; + pmd_val(pmdp[2]) = _PAGE_TABLE_INV; + pmd_val(pmdp[3]) = _PAGE_TABLE_INV; +} +extern inline void pte_clear(pte_t *ptep) +{ + pte_val(*ptep) = _PAGE_INVALID; +} -extern inline int pte_none(pte_t pte) { return ((pte_val(pte) & (_PAGE_INVALID | _PAGE_RO)) == _PAGE_INVALID); } -extern inline int pte_present(pte_t pte) { return pte_val(pte) & _PAGE_PRESENT; } -extern inline void pte_clear(pte_t *ptep) { pte_val(*ptep) = _PAGE_INVALID; } #define PTE_INIT(x) pte_clear(x) -extern inline int pmd_none(pmd_t pmd) { return pmd_val(pmd) & _PAGE_TABLE_INV; } -extern inline int pmd_bad(pmd_t pmd) { return (pmd_val(pmd) == 0); } -extern inline int pmd_present(pmd_t pmd) { return pmd_val(pmd) & _SEG_PRESENT; } -extern inline void pmd_clear(pmd_t * pmdp) { - pmd_val(pmdp[0]) = _PAGE_TABLE_INV; - pmd_val(pmdp[1]) = _PAGE_TABLE_INV; - pmd_val(pmdp[2]) = _PAGE_TABLE_INV; - pmd_val(pmdp[3]) = _PAGE_TABLE_INV; - } - /* - * The "pgd_xxx()" functions here are trivial for a folded two-level - * setup: the pgd is never bad, and a pmd always exists (as it's folded - * into the pgd entry) + * The following pte modification functions only work if + * pte_present() is true. Undefined behaviour if not.. */ -extern inline int pgd_none(pgd_t pgd) { return 0; } -extern inline int pgd_bad(pgd_t pgd) { return 0; } -extern inline int pgd_present(pgd_t pgd) { return 1; } -extern inline void pgd_clear(pgd_t * pgdp) { } +extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) +{ + pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot); + return pte; +} +extern inline pte_t pte_wrprotect(pte_t pte) +{ + pte_val(pte) |= _PAGE_RO; + return pte; +} -/* - * The following only work if pte_present() is true. - * Undefined behaviour if not.. - */ -extern inline int pte_write(pte_t pte) { return !(pte_val(pte) & _PAGE_RO); } -extern inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } -extern inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } +extern inline pte_t pte_mkwrite(pte_t pte) +{ + pte_val(pte) &= ~_PAGE_RO; + return pte; +} + +extern inline pte_t pte_mkclean(pte_t pte) +{ + /* We can't clear the changed bit atomically. The iske/and/sske + * sequence has a race condition with the page referenced bit. + * At the moment pte_mkclean is always followed by a pte_mkold. + * So its safe to ignore the problem for now. Hope this will + * never change ... */ + asm volatile ("sske %0,%1" + : : "d" (0), "a" (pte_val(pte))); + return pte; +} + +extern inline pte_t pte_mkdirty(pte_t pte) +{ + /* We can't set the changed bit atomically either. For now we + * set (!) the page referenced bit. */ + asm volatile ("sske %0,%1" + : : "d" (_PAGE_CHANGED|_PAGE_REFERENCED), + "a" (pte_val(pte))); + return pte; +} + +extern inline pte_t pte_mkold(pte_t pte) +{ + asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte))); + return pte; +} + +extern inline pte_t pte_mkyoung(pte_t pte) +{ + /* To set the referenced bit we read the first word from the real + * page with a special instruction: load using real address (lura). + * Isn't S/390 a nice architecture ?! */ + asm volatile ("lura 0,%0" : : "a" (pte_val(pte) & PAGE_MASK) : "0" ); + return pte; +} + +static inline int ptep_test_and_clear_young(pte_t *ptep) +{ + int ccode; -/* who needs that -extern inline int pte_read(pte_t pte) { return !(pte_val(pte) & _PAGE_INVALID); } -extern inline int pte_exec(pte_t pte) { return !(pte_val(pte) & _PAGE_INVALID); } -extern inline pte_t pte_rdprotect(pte_t pte) { pte_val(pte) |= _PAGE_INVALID; return pte; } -extern inline pte_t pte_exprotect(pte_t pte) { pte_val(pte) |= _PAGE_INVALID; return pte; } -extern inline pte_t pte_mkread(pte_t pte) { pte_val(pte) &= _PAGE_INVALID; return pte; } -extern inline pte_t pte_mkexec(pte_t pte) { pte_val(pte) &= _PAGE_INVALID; return pte; } -*/ + asm volatile ("rrbe 0,%1\n\t" + "ipm %0\n\t" + "srl %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep))); + return ccode & 2; +} -extern inline pte_t pte_wrprotect(pte_t pte) { pte_val(pte) |= _PAGE_RO; return pte; } -extern inline pte_t pte_mkwrite(pte_t pte) { pte_val(pte) &= ~_PAGE_RO ; return pte; } +static inline int ptep_test_and_clear_dirty(pte_t *ptep) +{ + int skey; + + asm volatile ("iske %0,%1" : "=d" (skey) : "a" (*ptep)); + if ((skey & _PAGE_CHANGED) == 0) + return 0; + /* We can't clear the changed bit atomically. For now we + * clear (!) the page referenced bit. */ + asm volatile ("sske %0,%1" + : : "d" (0), "a" (*ptep)); + return 1; +} -extern inline pte_t pte_mkclean(pte_t pte) { pte_val(pte) &= ~_PAGE_DIRTY; return pte; } -extern inline pte_t pte_mkdirty(pte_t pte) { pte_val(pte) |= _PAGE_DIRTY; return pte; } +static inline pte_t ptep_get_and_clear(pte_t *ptep) +{ + pte_t pte = *ptep; + pte_clear(ptep); + return pte; +} -extern inline pte_t pte_mkold(pte_t pte) { pte_val(pte) &= ~_PAGE_ACCESSED; return pte; } -extern inline pte_t pte_mkyoung(pte_t pte) { pte_val(pte) |= _PAGE_ACCESSED; return pte; } +static inline void ptep_set_wrprotect(pte_t *ptep) +{ + pte_t old_pte = *ptep; + set_pte(ptep, pte_wrprotect(old_pte)); +} +static inline void ptep_mkdirty(pte_t *ptep) +{ + pte_mkdirty(*ptep); +} /* * 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 mk_pte(page, pgprot) \ -({ pte_t __pte; pte_val(__pte) = __pa(((page)-mem_map)<<PAGE_SHIFT) + pgprot_val(pgprot); __pte; }) - -/* This takes a physical page address that is used by the remapping functions */ -#define mk_pte_phys(physpage, pgprot) \ -({ pte_t __pte; pte_val(__pte) = physpage + pgprot_val(pgprot); __pte; }) - -extern inline pte_t pte_modify(pte_t pte, pgprot_t newprot) -{ pte_val(pte) = (pte_val(pte) & PAGE_MASK) | pgprot_val(newprot); return pte; } +extern inline pte_t mk_pte_phys(unsigned long physpage, pgprot_t pgprot) +{ + pte_t __pte; + pte_val(__pte) = physpage + pgprot_val(pgprot); + return __pte; +} +#define mk_pte(page,pgprot) mk_pte_phys(__pa(((page)-mem_map)<<PAGE_SHIFT),pgprot) -#define page_address(page) ((page)->virtual) -#define pte_page(x) (mem_map+(unsigned long)((pte_val(pte) >> PAGE_SHIFT))) +#define pte_page(x) (mem_map+(unsigned long)((pte_val(x) >> PAGE_SHIFT))) #define pmd_page(pmd) \ -((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) + ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) /* to find an entry in a page-table-directory */ #define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) - -#define __pgd_offset(address) pgd_index(address) - #define pgd_offset(mm, address) ((mm)->pgd+pgd_index(address)) /* to find an entry in a kernel page-table-directory */ @@ -359,53 +432,39 @@ extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) /* Find an entry in the third-level page table.. */ #define pte_offset(pmd, address) \ -((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2)))) - - -/* We don't use pmd cache, so these are dummy routines */ -extern __inline__ pmd_t *get_pmd_fast(void) -{ - return (pmd_t *)0; -} - -extern __inline__ void free_pmd_fast(pmd_t *pmd) -{ -} - -extern __inline__ void free_pmd_slow(pmd_t *pmd) -{ -} - -extern void __handle_bad_pmd(pmd_t *pmd); -extern void __handle_bad_pmd_kernel(pmd_t *pmd); + ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2)))) /* - * The S390 doesn't have any external MMU info: the kernel page - * tables contain all the necessary information. + * A page-table entry has some bits we have to treat in a special way. + * Bits 0, 20 and bit 23 have to be zero, otherwise an specification + * exception will occur instead of a page translation exception. The + * specifiation exception has the bad habit not to store necessary + * information in the lowcore. + * Bit 21 and bit 22 are the page invalid bit and the page protection + * bit. We set both to indicate a swapped page. + * Bit 31 is used as the software page present bit. If a page is + * swapped this obviously has to be zero. + * This leaves the bits 1-19 and bits 24-30 to store type and offset. + * We use the 7 bits from 24-30 for the type and the 19 bits from 1-19 + * for the offset. + * 0| offset |0110|type |0 + * 00000000001111111111222222222233 + * 01234567890123456789012345678901 */ -extern inline void update_mmu_cache(struct vm_area_struct * vma, - unsigned long address, pte_t pte) +extern inline pte_t mk_swap_pte(unsigned long type, unsigned long offset) { + pte_t pte; + pte_val(pte) = (type << 1) | (offset << 12) | _PAGE_INVALID | _PAGE_RO; + pte_val(pte) &= 0x7ffff6fe; /* better to be paranoid */ + return pte; } -/* - * a page-table entry has only 19 bit for offset and 7 bit for type - * if bits 0, 20 or 23 are set, a translation specification exceptions occures, and it's - * hard to find out the failing address - * therefor, we zero out this bits - */ - -#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f) -#define SWP_OFFSET(entry) (((entry).val >> 12) & 0x7FFFF ) -#define SWP_ENTRY(type,offset) ((swp_entry_t) { (((type) << 1) | \ - ((offset) << 12) | \ - _PAGE_INVALID | _PAGE_RO) \ - & 0x7ffff6fe }) - -#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) -#define swp_entry_to_pte(x) ((pte_t) { (x).val }) +#define SWP_TYPE(entry) (((entry).val >> 1) & 0x3f) +#define SWP_OFFSET(entry) (((entry).val >> 12) & 0x7FFFF ) +#define SWP_ENTRY(type,offset) ((swp_entry_t) { pte_val(mk_swap_pte((type),(offset))) }) -#include <asm-generic/pgtable.h> +#define pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) }) +#define swp_entry_to_pte(x) ((pte_t) { (x).val }) #endif /* !__ASSEMBLY__ */ diff --git a/include/asm-s390/processor.h b/include/asm-s390/processor.h index 4629c822b..63f7a2a72 100644 --- a/include/asm-s390/processor.h +++ b/include/asm-s390/processor.h @@ -41,7 +41,7 @@ struct cpuinfo_S390 cpuid_t cpu_id; __u16 cpu_addr; __u16 cpu_nr; - unsigned long loops_per_sec; + unsigned long loops_per_jiffy; unsigned long *pgd_quick; unsigned long *pte_quick; unsigned long pgtable_cache_sz; @@ -87,13 +87,15 @@ struct thread_struct /* perform syscall argument validation (get/set_fs) */ mm_segment_t fs; per_struct per_info;/* Must be aligned on an 4 byte boundary*/ + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ }; typedef struct thread_struct thread_struct; #define INIT_MMAP \ { &init_mm, 0, 0, NULL, PAGE_SHARED, \ -VM_READ | VM_WRITE | VM_EXEC, 1, NULL, &init_mm.mmap } +VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NULL } #define INIT_THREAD { (struct pt_regs *) 0, \ { 0,{{0},{0},{0},{0},{0},{0},{0},{0},{0},{0}, \ @@ -108,12 +110,8 @@ VM_READ | VM_WRITE | VM_EXEC, 1, NULL, &init_mm.mmap } /* need to define ... */ #define start_thread(regs, new_psw, new_stackp) do { \ - unsigned long *u_stack = new_stackp; \ regs->psw.mask = _USER_PSW_MASK; \ - regs->psw.addr = new_psw | 0x80000000 ; \ - get_user(regs->gprs[2],u_stack); \ - get_user(regs->gprs[3],u_stack+1); \ - get_user(regs->gprs[4],u_stack+2); \ + regs->psw.addr = new_psw | 0x80000000; \ regs->gprs[15] = new_stackp ; \ } while (0) @@ -172,13 +170,33 @@ unsigned long get_wchan(struct task_struct *p); static inline void disabled_wait(unsigned long code) { char psw_buffer[2*sizeof(psw_t)]; + char ctl_buf[4]; psw_t *dw_psw = (psw_t *)(((unsigned long) &psw_buffer+sizeof(psw_t)-1) & -sizeof(psw_t)); dw_psw->mask = 0x000a0000; dw_psw->addr = code; - /* load disabled wait psw, the processor is dead afterwards */ - asm volatile ("lpsw 0(%0)" : : "a" (dw_psw)); + /* + * Store status and then load disabled wait psw, + * the processor is dead afterwards + */ + + asm volatile (" stctl 0,0,0(%1)\n" + " ni 0(%1),0xef\n" /* switch off protection */ + " lctl 0,0,0(%1)\n" + " stpt 0xd8\n" /* store timer */ + " stckc 0xe0\n" /* store clock comparator */ + " stpx 0x108\n" /* store prefix register */ + " stam 0,15,0x120\n" /* store access registers */ + " std 0,0x160\n" /* store f0 */ + " std 2,0x168\n" /* store f2 */ + " std 4,0x170\n" /* store f4 */ + " std 6,0x178\n" /* store f6 */ + " stm 0,15,0x180\n" /* store general registers */ + " stctl 0,15,0x1c0\n" /* store control registers */ + " oi 0(%1),0x10\n" /* fake protection bit */ + " lpsw 0(%0)" + : : "a" (dw_psw), "a" (&ctl_buf)); } #endif /* __ASM_S390_PROCESSOR_H */ diff --git a/include/asm-s390/ptrace.h b/include/asm-s390/ptrace.h index 60a698662..bf076e9b8 100644 --- a/include/asm-s390/ptrace.h +++ b/include/asm-s390/ptrace.h @@ -63,8 +63,8 @@ typedef struct unsigned storage_alt_space_ctl:1; unsigned :5; unsigned :16; - __u32 starting_addr; - __u32 ending_addr; + addr_t starting_addr; + addr_t ending_addr; } per_cr_bits __attribute__((packed)); typedef struct @@ -83,13 +83,25 @@ typedef struct unsigned perc_store_real_address:1; unsigned :3; unsigned :1; - unsigned atmid:5; + unsigned atmid_validity_bit:1; + unsigned atmid_psw_bit_32:1; + unsigned atmid_psw_bit_5:1; + unsigned atmid_psw_bit_16:1; + unsigned atmid_psw_bit_17:1; unsigned si:2; - __u32 address; /* 0x098 */ + addr_t address; /* 0x098 */ unsigned :4; /* 0x0a1 */ unsigned access_id:4; } per_lowcore_bits __attribute__((packed)); +typedef enum +{ + primary_asce, + ar_asce, + secondary_asce, + home_space_asce +} per_ai_codes; + typedef struct { union @@ -134,6 +146,8 @@ struct user_regs_struct * this is the way intel does it */ per_struct per_info; + addr_t ieee_instruction_pointer; + /* Used to give failing instruction back to user for ieee exceptions */ }; typedef struct user_regs_struct user_regs_struct; @@ -143,12 +157,8 @@ typedef struct pt_regs pt_regs; #ifdef __KERNEL__ #define user_mode(regs) (((regs)->psw.mask & PSW_PROBLEM_STATE) != 0) #define instruction_pointer(regs) ((regs)->psw.addr) - -struct thread_struct; -extern int sprintf_regs(int line,char *buff,struct task_struct * task, - struct thread_struct *tss,struct pt_regs * regs); -extern void show_regs(struct task_struct * task,struct thread_struct *tss, - struct pt_regs * regs); +extern void show_regs(struct pt_regs * regs); +extern char *task_show_regs(struct task_struct *task, char *buffer); #endif @@ -270,8 +280,9 @@ enum PT_CR_9=pt_off(per_info.control_regs.words.cr[0]), PT_CR_10=pt_off(per_info.control_regs.words.cr[1]), PT_CR_11=pt_off(per_info.control_regs.words.cr[2]), - PT_LASTOFF=PT_CR_11, - PT_ENDREGS=offsetof(user_regs_struct,per_info.lowcore.words.perc_atmid) + PT_IEEE_IP=pt_off(ieee_instruction_pointer), + PT_LASTOFF=PT_IEEE_IP, + PT_ENDREGS=sizeof(user_regs_struct)-1 }; #define PTRACE_AREA \ diff --git a/include/asm-s390/queue.h b/include/asm-s390/queue.h index 9771d3048..c817d23b3 100644 --- a/include/asm-s390/queue.h +++ b/include/asm-s390/queue.h @@ -70,6 +70,35 @@ static __inline__ void add_to_list(list **lhead,list *member) *lhead=member; } +static __inline__ list *remove_listhead(list **lhead) +{ + list *oldhead=*lhead; + + if(oldhead) + *lhead=(*lhead)->next; + return(oldhead); +} + +static __inline__ void add_to_list_tail(list **lhead,list *member) +{ + list *curr,*prev; + if(*lhead==NULL) + *lhead=member; + else + { + prev=*lhead; + for(curr=(*lhead)->next;curr!=NULL;curr=curr->next) + prev=curr; + prev->next=member; + } +} +static __inline__ void add_to_list_tail_null(list **lhead,list *member) +{ + member->next=NULL; + add_to_list_tail_null(lhead,member); +} + + static __inline__ int is_in_list(list *lhead,list *member) { list *curr; @@ -96,6 +125,7 @@ static __inline__ int get_prev(list *lhead,list *member,list **prev) } + static __inline__ int remove_from_list(list **lhead,list *member) { list *prev; @@ -112,6 +142,29 @@ static __inline__ int remove_from_list(list **lhead,list *member) return(FALSE); } +static __inline__ int remove_from_queue(qheader *qhead,queue *member) +{ + queue *prev; + + if(get_prev(qhead->head,(list *)member,(list **)&prev)) + { + + if(prev) + { + prev->next=member->next; + if(prev->next==NULL) + qhead->tail=prev; + } + else + { + if(qhead->head==qhead->tail) + qhead->tail=NULL; + qhead->head=member->next; + } + return(TRUE); + } + return(FALSE); +} diff --git a/include/asm-s390/resource.h b/include/asm-s390/resource.h index 4e5d91143..bc2520e1d 100644 --- a/include/asm-s390/resource.h +++ b/include/asm-s390/resource.h @@ -23,8 +23,8 @@ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ #define RLIMIT_AS 9 /* address space limit */ -#define RLIMIT_AS 10 /* maximum file locks held */ - +#define RLIMIT_LOCKS 10 /* maximum file locks held */ + #define RLIM_NLIMITS 11 /* @@ -37,17 +37,17 @@ #define INIT_RLIMITS \ { \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { _STK_LIM, LONG_MAX }, \ - { 0, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { _STK_LIM, RLIM_INFINITY }, \ + { 0, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { 0, 0 }, \ { INR_OPEN, INR_OPEN }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ - { LONG_MAX, LONG_MAX }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ + { RLIM_INFINITY, RLIM_INFINITY }, \ } #endif /* __KERNEL__ */ diff --git a/include/asm-s390/s390-gdbregs.h b/include/asm-s390/s390-gdbregs.h index af708d51d..9527f575e 100644 --- a/include/asm-s390/s390-gdbregs.h +++ b/include/asm-s390/s390-gdbregs.h @@ -8,13 +8,14 @@ * used both by the linux kernel for remote debugging & gdb */ -/* Say how long (ordinary) registers are. This is a piece of bogosity - used in push_word and a few other places; REGISTER_RAW_SIZE is the - real way to know how big a register is. */ #ifndef _S390_GDBREGS_H #define _S390_GDBREGS_H +#ifdef __KERNEL__ #include <asm/s390-regs-common.h> +#else +#include <s390/s390-regs-common.h> +#endif #define S390_MAX_INSTR_SIZE 6 #define NUM_REGS (2+NUM_GPRS+NUM_ACRS+NUM_CRS+1+NUM_FPRS) #define FIRST_ACR (2+NUM_GPRS) diff --git a/include/asm-s390/s390-regs-common.h b/include/asm-s390/s390-regs-common.h index aa349a69d..7934b3dab 100644 --- a/include/asm-s390/s390-regs-common.h +++ b/include/asm-s390/s390-regs-common.h @@ -16,8 +16,9 @@ #ifndef __ASSEMBLY__ #include <asm/types.h> #endif - +#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) #define REGISTER_SIZE 4 +#endif #define NUM_GPRS 16 #define GPR_SIZE 4 #define PSW_MASK_SIZE 4 @@ -41,8 +42,6 @@ typedef struct __u32 addr; } psw_t __attribute__ ((aligned(8))); -typedef __u32 gpr_t; - /* 2 __u32's are used for floats instead to compile with a __STRICT_ANSI__ defined */ typedef union { @@ -71,6 +70,13 @@ typedef struct freg_t fprs[NUM_FPRS]; } s390_fp_regs; +#define FPC_EXCEPTION_MASK 0xF8000000 +#define FPC_FLAGS_MASK 0x00F80000 +#define FPC_DXC_MASK 0x0000FF00 +#define FPC_RM_MASK 0x00000003 +#define FPC_VALID_MASK ((FPC_EXCEPTION_MASK|FPC_FLAGS_MASK| \ + FPC_DXC_MASK|FPC_RM_MASK)) + /* gdb structures & the kernel have this much always in common */ @@ -90,9 +96,11 @@ typedef struct #define S390_BREAKPOINT_U16 ((__u16)0x0001) #define S390_SYSCALL_OPCODE ((__u16)0x0a00) #define S390_SYSCALL_SIZE 2 +#if defined(WANT_S390_TGT_DEFS) || defined(__KERNEL__) #define ADDR_BITS_REMOVE(addr) ((addr)&0x7fffffff) #endif #endif +#endif diff --git a/include/asm-s390/s390_ext.h b/include/asm-s390/s390_ext.h new file mode 100644 index 000000000..08a080441 --- /dev/null +++ b/include/asm-s390/s390_ext.h @@ -0,0 +1,30 @@ +#ifndef _S390_EXTINT_H +#define _S390_EXTINT_H + +/* + * include/asm-s390/s390_ext.h + * + * S390 version + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Author(s): Holger Smolinski (Holger.Smolinski@de.ibm.com), + * Martin Schwidefsky (schwidefsky@de.ibm.com) + */ + +typedef void (*ext_int_handler_t)(struct pt_regs *regs, __u16 code); + +/* + * Warning: if you change ext_int_info_t you have to change the + * external interrupt handler in entry.S too. + */ +typedef struct ext_int_info_t { + struct ext_int_info_t *next; + ext_int_handler_t handler; + __u16 code; +} __attribute__ ((packed)) ext_int_info_t; + +extern ext_int_info_t *ext_int_hash[]; + +int register_external_interrupt(__u16 code, ext_int_handler_t handler); +int unregister_external_interrupt(__u16 code, ext_int_handler_t handler); + +#endif diff --git a/include/asm-s390/s390dyn.h b/include/asm-s390/s390dyn.h index 960a81b43..a728ddf33 100644 --- a/include/asm-s390/s390dyn.h +++ b/include/asm-s390/s390dyn.h @@ -12,28 +12,20 @@ struct _devreg; -typedef int (* oper_handler_func_t)( int irq, - struct _devreg *dreg); -typedef void (* io_handler_func_t) ( int irq, - __u32 intparm ); -typedef void ( * not_oper_handler_func_t)( int irq, - int status ); +typedef int (* oper_handler_func_t)( int irq, + struct _devreg *dreg); + +typedef struct _devreg_hc_t { + __u16 ctype; + __u8 cmode; + __u16 dtype; + __u8 dmode; + } __attribute__ ((packed)) devreg_hc_t; typedef struct _devreg { union { - struct _hc { - __u16 ctype; - __u8 cmode; - __u16 dtype; - __u8 dmode; - } hc; /* has controller info */ - - struct _hnc { - __u16 dtype; - __u8 dmode; - __u16 res1; - __u8 res2; - } hnc; /* has no controller info */ + int devno; + devreg_hc_t hc; /* has controller info */ } ci; int flag; @@ -46,15 +38,13 @@ typedef struct _devreg { #define DEVREG_MATCH_DEV_TYPE 0x00000002 #define DEVREG_MATCH_CU_TYPE 0x00000004 #define DEVREG_NO_CU_INFO 0x00000008 +#define DEVREG_NO_DEV_INFO 0x00000010 +#define DEVREG_TYPE_DEVNO 0x80000000 +#define DEVREG_TYPE_DEVCHARS 0x40000000 -int s390_device_register ( devreg_t *drinfo ); -int s390_device_deregister ( devreg_t *dreg ); -int s390_request_irq_special( int irq, - io_handler_func_t io_handler, - not_oper_handler_func_t not_oper_handler, - unsigned long irqflags, - const char *devname, - void *dev_id); +int s390_device_register ( devreg_t *drinfo ); +int s390_device_unregister( devreg_t *dreg ); +devreg_t * s390_search_devreg ( ioinfo_t *ioinfo ); #endif /* __s390dyn */ diff --git a/include/asm-s390/s390io.h b/include/asm-s390/s390io.h index 8ba9c11db..1a5a0f094 100644 --- a/include/asm-s390/s390io.h +++ b/include/asm-s390/s390io.h @@ -47,25 +47,35 @@ typedef struct _ioinfo { unsigned int s_pend : 1; /* status pending condition */ unsigned int pgid : 1; /* "path group ID" is valid */ unsigned int pgid_supp : 1; /* "path group ID" command is supported */ - unsigned int unused : (sizeof(unsigned int)*8 - 18); /* unused */ + unsigned int esid : 1; /* Ext. SenseID supported by HW */ + unsigned int rcd : 1; /* RCD supported by HW */ + unsigned int repnone : 1; /* don't call IRQ handler on interrupt */ + unsigned int newreq : 1; /* new register interface */ + unsigned int dval : 1; /* device number valid */ + unsigned int unknown : 1; /* unknown device - if SenseID failed */ + unsigned int unused : (sizeof(unsigned int)*8 - 24); /* unused */ } __attribute__ ((packed)) flags; } ui; unsigned long u_intparm; /* user interruption parameter */ senseid_t senseid; /* SenseID info */ irq_desc_t irq_desc; /* irq descriptor */ + not_oper_handler_func_t nopfunc; /* not oper handler */ __u8 ulpm; /* logical path mask used for I/O */ __u8 opm; /* path mask of operational paths */ + __u16 devno; /* device number */ pgid_t pgid; /* path group ID */ schib_t schib; /* subchannel information block */ orb_t orb; /* operation request block */ devstat_t devstat; /* device status */ ccw1_t *qcpa; /* queued channel program */ ccw1_t senseccw; /* ccw for sense command */ + __u8 sense_data[32];/* buffer for basic sense */ unsigned int stctl; /* accumulated status control from irb */ unsigned long qintparm; /* queued interruption parameter */ unsigned long qflag; /* queued flags */ - unsigned char qlpm; /* queued logical path mask */ + __u8 qlpm; /* queued logical path mask */ + __u32 syncnt; /* sync I/O recursive usage count */ } __attribute__ ((aligned(8))) ioinfo_t; diff --git a/include/asm-s390/s390mach.h b/include/asm-s390/s390mach.h index 56349777a..961e17ecf 100644 --- a/include/asm-s390/s390mach.h +++ b/include/asm-s390/s390mach.h @@ -12,14 +12,21 @@ #include <asm/types.h> -// -// machine-check-interruption code -// -typedef struct _mcic { +typedef struct _mci { __u32 to_be_defined_1 : 9; __u32 cp : 1; /* channel-report pending */ __u32 to_be_defined_2 : 22; __u32 to_be_defined_3; + } mci_t; + +// +// machine-check-interruption code +// +typedef struct _mcic { + union _mcc { + __u64 mcl; /* machine check int. code - long info */ + mci_t mcd; /* machine check int. code - details */ + } mcc; } __attribute__ ((packed)) mcic_t; // @@ -37,29 +44,63 @@ typedef struct _crw { __u32 rsid : 16; /* reporting-source ID */ } __attribute__ ((packed)) crw_t; +#define CRW_RSC_MONITOR 0x2 /* monitoring facility */ +#define CRW_RSC_SCH 0x3 /* subchannel */ +#define CRW_RSC_CPATH 0x4 /* channel path */ +#define CRW_RSC_CONFIG 0x9 /* configuration-alert facility */ +#define CRW_RSC_CSS 0xB /* channel subsystem */ + +#define CRW_ERC_EVENT 0x00 /* event information pending */ +#define CRW_ERC_AVAIL 0x01 /* available */ +#define CRW_ERC_INIT 0x02 /* initialized */ +#define CRW_ERC_TERROR 0x03 /* temporary error */ +#define CRW_ERC_IPARM 0x04 /* installed parm initialized */ +#define CRW_ERC_TERM 0x05 /* terminal */ +#define CRW_ERC_PERRN 0x06 /* perm. error, fac. not init */ +#define CRW_ERC_PERRI 0x07 /* perm. error, facility init */ +#define CRW_ERC_PMOD 0x08 /* installed parameters modified */ + +#define MAX_CRW_PENDING 1024 +#define MAX_MACH_PENDING 1024 + // // CRW Entry // typedef struct _crwe { - crw_t crw; - crw_t *crw_next; + crw_t crw; + struct _crwe *crwe_next; } __attribute__ ((packed)) crwe_t; -typedef struct _mchchk_queue_element { - spinlock_t lock; - unsigned int status; - mcic_t mcic; - crwe_t *crwe; /* CRW if applicable */ - struct mchchk_queue_element *next; - struct mchchk_queue_element *prev; -} mchchk_queue_element_t; +typedef struct _mache { + spinlock_t lock; + unsigned int status; + mcic_t mcic; + union _mc { + crwe_t *crwe; /* CRW if applicable */ + } mc; + struct _mache *next; + struct _mache *prev; +} mache_t; #define MCHCHK_STATUS_TO_PROCESS 0x00000001 #define MCHCHK_STATUS_IN_PROGRESS 0x00000002 #define MCHCHK_STATUS_WAITING 0x00000004 -void s390_init_machine_check ( void ); -void __init s390_do_machine_check ( void ); -void __init s390_machine_check_handler( struct semaphore * ); +void s390_init_machine_check( void ); +void s390_do_machine_check ( void ); +void s390_do_crw_pending ( crwe_t *pcrwe ); + +extern __inline__ int stcrw( __u32 *pcrw ) +{ + int ccode; + + __asm__ __volatile__( + "STCRW 0(%1)\n\t" + "IPM %0\n\t" + "SRL %0,28\n\t" + : "=d" (ccode) : "a" (pcrw) + : "cc", "1" ); + return ccode; +} #endif /* __s390mach */ diff --git a/include/asm-s390/scatterlist.h b/include/asm-s390/scatterlist.h new file mode 100644 index 000000000..e9cfe86f6 --- /dev/null +++ b/include/asm-s390/scatterlist.h @@ -0,0 +1,13 @@ +#ifndef _ASMS390X_SCATTERLIST_H +#define _ASMS390X_SCATTERLIST_H + +struct scatterlist { + char * address; /* Location data is to be transferred to */ + char * alt_address; /* Location of actual if address is a + * dma indirect buffer. NULL otherwise */ + unsigned int length; +}; + +#define ISA_DMA_THRESHOLD (0xffffffffffffffff) + +#endif /* _ASMS390X_SCATTERLIST_H */ diff --git a/include/asm-s390/semaphore.h b/include/asm-s390/semaphore.h index fc903d772..dfd49e1d7 100644 --- a/include/asm-s390/semaphore.h +++ b/include/asm-s390/semaphore.h @@ -36,7 +36,7 @@ struct semaphore { #define DECLARE_MUTEX(name) __DECLARE_SEMAPHORE_GENERIC(name,1) #define DECLARE_MUTEX_LOCKED(name) __DECLARE_SEMAPHORE_GENERIC(name,0) -extern inline void sema_init (struct semaphore *sem, int val) +static inline void sema_init (struct semaphore *sem, int val) { *sem = (struct semaphore)__SEMAPHORE_INITIALIZER((*sem),val); } @@ -61,13 +61,13 @@ asmlinkage int __down_interruptible(struct semaphore * sem); asmlinkage int __down_trylock(struct semaphore * sem); asmlinkage void __up(struct semaphore * sem); -extern inline void down(struct semaphore * sem) +static inline void down(struct semaphore * sem) { if (atomic_dec_return(&sem->count) < 0) __down(sem); } -extern inline int down_interruptible(struct semaphore * sem) +static inline int down_interruptible(struct semaphore * sem) { int ret = 0; @@ -76,7 +76,7 @@ extern inline int down_interruptible(struct semaphore * sem) return ret; } -extern inline int down_trylock(struct semaphore * sem) +static inline int down_trylock(struct semaphore * sem) { int ret = 0; @@ -85,7 +85,7 @@ extern inline int down_trylock(struct semaphore * sem) return ret; } -extern inline void up(struct semaphore * sem) +static inline void up(struct semaphore * sem) { if (atomic_inc_return(&sem->count) <= 0) __up(sem); @@ -136,7 +136,7 @@ struct rw_semaphore { #define DECLARE_RWSEM_READ_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,RW_LOCK_BIAS-1) #define DECLARE_RWSEM_WRITE_LOCKED(name) __DECLARE_RWSEM_GENERIC(name,0) -extern inline void init_rwsem(struct rw_semaphore *sem) +static inline void init_rwsem(struct rw_semaphore *sem) { atomic_set(&sem->count, RW_LOCK_BIAS); sem->read_bias_granted = 0; @@ -149,7 +149,7 @@ extern void __down_read_failed(int, struct rw_semaphore *); extern void __down_write_failed(int, struct rw_semaphore *); extern void __rwsem_wake(int, struct rw_semaphore *); -extern inline void down_read(struct rw_semaphore *sem) +static inline void down_read(struct rw_semaphore *sem) { int count; count = atomic_dec_return(&sem->count); @@ -157,7 +157,7 @@ extern inline void down_read(struct rw_semaphore *sem) __down_read_failed(count, sem); } -extern inline void down_write(struct rw_semaphore *sem) +static inline void down_write(struct rw_semaphore *sem) { int count; count = atomic_add_return (-RW_LOCK_BIAS, &sem->count); @@ -169,7 +169,7 @@ extern inline void down_write(struct rw_semaphore *sem) * case is when there was a writer waiting, and we've * bumped the count to 0: we must wake the writer up. */ -extern inline void up_read(struct rw_semaphore *sem) +static inline void up_read(struct rw_semaphore *sem) { int count; count = atomic_inc_return(&sem->count); @@ -180,7 +180,7 @@ extern inline void up_read(struct rw_semaphore *sem) /* releasing the writer is easy -- just release it and * wake up any sleepers. */ -extern inline void up_write(struct rw_semaphore *sem) +static inline void up_write(struct rw_semaphore *sem) { int count; count = atomic_add_return(RW_LOCK_BIAS, &sem->count); diff --git a/include/asm-s390/setup.h b/include/asm-s390/setup.h index 6a9449a52..9e97f2dc0 100644 --- a/include/asm-s390/setup.h +++ b/include/asm-s390/setup.h @@ -41,6 +41,7 @@ #define MACHINE_IS_VM (MACHINE_FLAGS & 1) #define MACHINE_HAS_IEEE (MACHINE_FLAGS & 2) #define MACHINE_IS_P390 (MACHINE_FLAGS & 4) +#define MACHINE_HAS_CSP (MACHINE_FLAGS & 8) #define RAMDISK_ORIGIN 0x800000 #define RAMDISK_BLKSIZE 0x1000 diff --git a/include/asm-s390/sigcontext.h b/include/asm-s390/sigcontext.h index 610f20e26..25c65e26a 100644 --- a/include/asm-s390/sigcontext.h +++ b/include/asm-s390/sigcontext.h @@ -2,12 +2,15 @@ * include/asm-s390/sigcontext.h * * S390 version - * Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation + * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation */ #ifndef _ASM_S390_SIGCONTEXT_H #define _ASM_S390_SIGCONTEXT_H -#include <asm/s390-regs-common.h> + +#define __NUM_GPRS 16 +#define __NUM_FPRS 16 +#define __NUM_ACRS 16 /* Has to be at least _NSIG_WORDS from asm/signal.h @@ -15,20 +18,39 @@ #define _SIGCONTEXT_NSIG 64 #define _SIGCONTEXT_NSIG_BPW 32 /* Size of stack frame allocated when calling signal handler. */ -#define __SIGNAL_FRAMESIZE STACK_FRAME_OVERHEAD -#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) -#define SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) +#define __SIGNAL_FRAMESIZE 96 +#define _SIGCONTEXT_NSIG_WORDS (_SIGCONTEXT_NSIG / _SIGCONTEXT_NSIG_BPW) +#define _SIGMASK_COPY_SIZE (sizeof(unsigned long)*_SIGCONTEXT_NSIG_WORDS) + +typedef struct +{ + unsigned long mask; + unsigned long addr; +} _psw_t __attribute__ ((aligned(8))); + +typedef struct +{ + _psw_t psw; + unsigned long gprs[__NUM_GPRS]; + unsigned int acrs[__NUM_ACRS]; +} _s390_regs_common __attribute__ ((packed)); + +typedef struct +{ + unsigned int fpc; + double fprs[__NUM_FPRS]; +} _s390_fp_regs; typedef struct { - s390_regs_common regs; - s390_fp_regs fpregs; -} sigregs; + _s390_regs_common regs; + _s390_fp_regs fpregs; +} _sigregs; struct sigcontext { unsigned long oldmask[_SIGCONTEXT_NSIG_WORDS]; - sigregs *sregs; + _sigregs *sregs; }; diff --git a/include/asm-s390/siginfo.h b/include/asm-s390/siginfo.h index 1efd4e1c3..876e8baae 100644 --- a/include/asm-s390/siginfo.h +++ b/include/asm-s390/siginfo.h @@ -85,6 +85,25 @@ typedef struct siginfo { #define si_band _sifields._sigpoll._band #define si_fd _sifields._sigpoll._fd +#ifdef __KERNEL__ +#define __SI_MASK 0xffff0000 +#define __SI_KILL (0 << 16) +#define __SI_TIMER (1 << 16) +#define __SI_POLL (2 << 16) +#define __SI_FAULT (3 << 16) +#define __SI_CHLD (4 << 16) +#define __SI_RT (5 << 16) +#define __SI_CODE(T,N) ((T) << 16 | ((N) & 0xffff)) +#else +#define __SI_KILL 0 +#define __SI_TIMER 0 +#define __SI_POLL 0 +#define __SI_FAULT 0 +#define __SI_CHLD 0 +#define __SI_RT 0 +#define __SI_CODE(T,N) (N) +#endif + /* * si_code values * Digital reserves positive values for kernel-generated signals. @@ -202,4 +221,20 @@ typedef struct sigevent { #define sigev_notify_function _sigev_un._sigev_thread._function #define sigev_notify_attributes _sigev_un._sigev_thread._attribute +#ifdef __KERNEL__ +#include <linux/string.h> + +extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from) +{ + if (from->si_code < 0) + memcpy(to, from, sizeof(siginfo_t)); + else + /* _sigchld is currently the largest know union member */ + memcpy(to, from, 3*sizeof(int) + sizeof(from->_sifields._sigchld)); +} + +extern int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from); + +#endif /* __KERNEL__ */ + #endif diff --git a/include/asm-s390/sigp.h b/include/asm-s390/sigp.h index 5154a34a5..bbf97d5c9 100644 --- a/include/asm-s390/sigp.h +++ b/include/asm-s390/sigp.h @@ -41,83 +41,6 @@ typedef enum sigp_store_extended_status_at_address } sigp_order_code; -#if 0 -/* - * these definitions are not used at the moment, but we might need - * them in future. - */ -typedef struct -{ - __u64 cpu_timer; - psw_t current_psw; - __u32 prefix; - __u32 access_regs[16]; - __u64 float_regs[4]; - __u32 gpr_regs[16]; - __u32 control_regs[16]; -} sigp_status __attribute__((packed)); - -typedef struct -{ - __u8 unused1[216]; - __u64 cpu_timer; - psw_t current_psw; - __u32 prefix; - __u32 access_regs[16]; - __u64 float_regs[4]; - __u32 gpr_regs[16]; - __u32 control_regs[16]; -} sigp_status_512 __attribute__((packed)); - -typedef struct -{ - __u32 extended_save_area_address; - __u64 cpu_timer; - psw_t current_psw; - __u32 prefix; - __u32 access_regs[16]; - __u64 float_regs[4]; - __u32 gpr_regs[16]; - __u32 control_regs[16]; -} sigp_extended_status __attribute__((packed)); - -typedef struct -{ - __u8 unused1[212]; - __u32 extended_save_area_address; - __u64 cpu_timer; - psw_t current_psw; - __u32 prefix; - __u32 access_regs[16]; - __u64 float_regs[4]; - __u32 gpr_regs[16]; - __u32 control_regs[16]; -} sigp_extended_status_512 __attribute__((packed)); - -typedef struct -{ - __u64 bfp_float_regs[16]; - __u32 bfp_float_control_reg; - __u8 reserved[12]; -} sigp_extended_save_area __attribute__ ((packed)); - -typedef struct -{ - unsigned equipment_check:1; - unsigned unassigned1:20; - unsigned incorrect_state:1; - unsigned invalid_parameter:1; - unsigned external_call_pending:1; - unsigned stopped:1; - unsigned operator_intervening:1; - unsigned check_stop:1; - unsigned unassigned2:1; - unsigned inoperative:1; - unsigned invalid_order:1; - unsigned receiver_check:1; -} sigp_status_bits __attribute__((packed)); -#endif - typedef __u32 sigp_status_word; typedef enum @@ -140,16 +63,15 @@ typedef enum ec_restart, ec_halt, ec_power_off, + ec_ptlb, ec_bit_last } ec_bit_sig; /* Signals which come with a parameter area, synchronous */ typedef enum { - ec_set_ctl, - ec_get_ctl, - ec_set_ctl_masked, - ec_cmd_last + ec_callback_async, + ec_callback_sync } ec_cmd_sig; /* state information for synchronous signals */ @@ -166,26 +88,10 @@ typedef struct ec_ext_call ec_cmd_sig cmd; atomic_t status; struct ec_ext_call *next; - void *parms; + void (*func)(void *info); + void *info; } ec_ext_call; -/* parameter area for the ec_set_ctl and ec_get_ctl signal */ -typedef struct -{ - __u16 start_ctl; - __u16 end_ctl; - __u32 cregs[16]; -} ec_creg_parms; - -/* parameter area for the ec_set_ctl_masked signal */ -typedef struct -{ - __u16 start_ctl; - __u16 end_ctl; - __u32 orvals[16]; - __u32 andvals[16]; -} ec_creg_mask_parms; - /* * Signal processor */ diff --git a/include/asm-s390/smp.h b/include/asm-s390/smp.h index d7f246bb7..2922f398a 100644 --- a/include/asm-s390/smp.h +++ b/include/asm-s390/smp.h @@ -13,7 +13,7 @@ #ifndef __ASSEMBLY__ #include <asm/lowcore.h> -#include <linux/tasks.h> // FOR NR_CPUS definition only. +#include <linux/threads.h> // FOR NR_CPUS definition only. #include <linux/kernel.h> // FOR FASTCALL definition #define smp_processor_id() (current->processor) @@ -31,7 +31,6 @@ #define PROC_CHANGE_PENALTY 20 /* Schedule penalty */ -extern unsigned long ipi_count; extern void count_cpus(void); extern __inline__ int cpu_logical_map(int cpu) @@ -67,10 +66,11 @@ typedef struct __u16 cpu; } sigp_info; -sigp_ccode smp_ext_call_sync(int cpu, ec_cmd_sig cmd,void *parms); -sigp_ccode smp_ext_call_async(int cpu, ec_bit_sig sig); -void smp_ext_call_sync_others(ec_cmd_sig cmd, void *parms); -void smp_ext_call_async_others(ec_bit_sig sig); +sigp_ccode +smp_ext_call(int cpu, void (*callback)(void *info), void *info, int wait); +void smp_ext_call_others(void (*callback)(void *info), void *info, int wait); +sigp_ccode smp_ext_bitcall(int cpu, ec_bit_sig sig); +void smp_ext_bitcall_others(ec_bit_sig sig); int smp_signal_others(sigp_order_code order_code,__u32 parameter, int spin,sigp_info *info); diff --git a/include/asm-s390/smplock.h b/include/asm-s390/smplock.h index 4ebd38025..1f6485fb0 100644 --- a/include/asm-s390/smplock.h +++ b/include/asm-s390/smplock.h @@ -7,10 +7,12 @@ */ #include <linux/interrupt.h> -#include <asm/spinlock.h> +#include <linux/spinlock.h> extern spinlock_t kernel_flag; +#define kernel_locked() spin_is_locked(&kernel_flag) + /* * Release global kernel lock and global interrupt lock */ diff --git a/include/asm-s390/socket.h b/include/asm-s390/socket.h index 0d00c3b54..7b52cdb8f 100644 --- a/include/asm-s390/socket.h +++ b/include/asm-s390/socket.h @@ -51,6 +51,8 @@ #define SO_TIMESTAMP 29 #define SCM_TIMESTAMP SO_TIMESTAMP +#define SO_ACCEPTCONN 30 + /* Nast libc5 fixup - bletch */ #if defined(__KERNEL__) /* Socket types. */ diff --git a/include/asm-s390/spinlock.h b/include/asm-s390/spinlock.h index 9c7725b55..52bcfc739 100644 --- a/include/asm-s390/spinlock.h +++ b/include/asm-s390/spinlock.h @@ -24,37 +24,36 @@ typedef struct { #define SPIN_LOCK_UNLOCKED (spinlock_t) { 0 } #define spin_lock_init(lp) do { (lp)->lock = 0; } while(0) -#define spin_unlock_wait(lp) do { barrier(); } while((volatile spinlock_t *)(lp)->lock) +#define spin_unlock_wait(lp) do { barrier(); } while(((volatile spinlock_t *)(lp))->lock) #define spin_is_locked(x) ((x)->lock != 0) extern inline void spin_lock(spinlock_t *lp) { - __asm__ __volatile(" lhi 1,-1\n" - "0: slr 0,0\n" - " cs 0,1,%1\n" - " jl 0b" - : "=m" (lp->lock) - : "0" (lp->lock) : "0", "1"); + __asm__ __volatile(" bras 1,1f\n" + "0: diag 0,0,68\n" + "1: slr 0,0\n" + " cs 0,1,%1\n" + " jl 0b\n" + : "=m" (lp->lock) + : "0" (lp->lock) : "0", "1", "cc" ); } extern inline int spin_trylock(spinlock_t *lp) { unsigned long result; __asm__ __volatile(" slr %1,%1\n" - " lhi 0,-1\n" - "0: cs %1,0,%0" + " basr 1,0\n" + "0: cs %1,1,%0" : "=m" (lp->lock), "=&d" (result) - : "0" (lp->lock) : "0"); + : "0" (lp->lock) : "1", "cc" ); return !result; } - - extern inline void spin_unlock(spinlock_t *lp) { __asm__ __volatile(" xc 0(4,%0),0(%0)\n" " bcr 15,0" - : /* no output */ : "a" (lp) ); + : /* no output */ : "a" (lp) : "memory", "cc" ); } /* @@ -76,45 +75,42 @@ typedef struct { #define read_lock(rw) \ asm volatile(" l 2,%0\n" \ - "0: sll 2,1\n" \ - " srl 2,1\n" /* clear high (=write) bit */ \ - " lr 3,2\n" \ - " ahi 3,1\n" /* one more reader */ \ + " j 1f\n" \ + "0: diag 0,0,68\n" \ + "1: la 2,0(2)\n" /* clear high (=write) bit */ \ + " la 3,1(2)\n" /* one more reader */ \ " cs 2,3,%0\n" /* try to write new value */ \ " jl 0b" \ - : "+m" ((rw)->lock) : : "2", "3" ); + : "+m" ((rw)->lock) : : "2", "3", "cc" ); #define read_unlock(rw) \ asm volatile(" l 2,%0\n" \ - "0: lr 3,2\n" \ + " j 1f\n" \ + "0: diag 0,0,68\n" \ + "1: lr 3,2\n" \ " ahi 3,-1\n" /* one less reader */ \ " cs 2,3,%0\n" \ " jl 0b" \ - : "+m" ((rw)->lock) : : "2", "3" ); + : "+m" ((rw)->lock) : : "2", "3", "cc" ); #define write_lock(rw) \ asm volatile(" lhi 3,1\n" \ " sll 3,31\n" /* new lock value = 0x80000000 */ \ - "0: slr 2,2\n" /* old lock value must be 0 */ \ + " j 1f\n" \ + "0: diag 0,0,68\n" \ + "1: slr 2,2\n" /* old lock value must be 0 */ \ " cs 2,3,%0\n" \ " jl 0b" \ - : "+m" ((rw)->lock) : : "2", "3" ); + : "+m" ((rw)->lock) : : "2", "3", "cc" ); #define write_unlock(rw) \ asm volatile(" slr 3,3\n" /* new lock value = 0 */ \ - "0: lhi 2,1\n" \ + " j 1f\n" \ + "0: diag 0,0,68\n" \ + "1: lhi 2,1\n" \ " sll 2,31\n" /* old lock value must be 0x80000000 */ \ " cs 2,3,%0\n" \ " jl 0b" \ - : "+m" ((rw)->lock) : : "2", "3" ); + : "+m" ((rw)->lock) : : "2", "3", "cc" ); #endif /* __ASM_SPINLOCK_H */ - - - - - - - - - diff --git a/include/asm-s390/stat.h b/include/asm-s390/stat.h index be52ef679..a0edcab80 100644 --- a/include/asm-s390/stat.h +++ b/include/asm-s390/stat.h @@ -50,36 +50,30 @@ struct stat { * insane amounts of padding around dev_t's. */ struct stat64 { - unsigned short st_dev; unsigned char __pad0[6]; - - unsigned long long st_ino; + unsigned short st_dev; + unsigned int __pad1; +#define STAT64_HAS_BROKEN_ST_INO 1 + unsigned long __st_ino; unsigned int st_mode; unsigned int st_nlink; - unsigned long st_uid; unsigned long st_gid; - + unsigned char __pad2[6]; unsigned short st_rdev; - unsigned char __pad3[10]; - + unsigned int __pad3; long long st_size; unsigned long st_blksize; - - unsigned long st_blocks; /* Number 512-byte blocks allocated. */ - unsigned long __pad4; /* future possible st_blocks high bits */ - + unsigned char __pad4[4]; + unsigned long __pad5; /* future possible st_blocks high bits */ + unsigned long st_blocks; /* Number 512-byte blocks allocated. */ unsigned long st_atime; - unsigned long __pad5; - - unsigned long st_mtime; unsigned long __pad6; - + unsigned long st_mtime; + unsigned long __pad7; unsigned long st_ctime; - unsigned long __pad7; /* will be high 32 bits of ctime someday */ - - unsigned long __unused1; - unsigned long __unused2; + unsigned long __pad8; /* will be high 32 bits of ctime someday */ + unsigned long long st_ino; }; #endif diff --git a/include/asm-s390/string.h b/include/asm-s390/string.h index 2e8081912..304979b83 100644 --- a/include/asm-s390/string.h +++ b/include/asm-s390/string.h @@ -40,24 +40,29 @@ #undef __HAVE_ARCH_STRSTR extern void *memset(void *, int, size_t); +extern void *memcpy(void *, const void *, size_t); +extern void *memmove(void *, const void *, size_t); +extern char *strncpy(char *, const char *, size_t); +extern int strcmp(const char *,const char *); -extern inline void * memchr(const void * cs,int c,size_t count) +static inline void * memchr(const void * cs,int c,size_t count) { void *ptr; __asm__ __volatile__ (" lr 0,%2\n" + " lr 1,%1\n" " la %0,0(%3,%1)\n" - "0: srst %0,%1\n" + "0: srst %0,1\n" " jo 0b\n" " brc 13,1f\n" " slr %0,%0\n" "1:" - : "=a" (ptr) : "a" (cs), "d" (c), "d" (count) - : "cc", "0" ); + : "=&a" (ptr) : "a" (cs), "d" (c), "d" (count) + : "cc", "0", "1" ); return ptr; } -extern __inline__ char *strcpy(char *dest, const char *src) +static __inline__ char *strcpy(char *dest, const char *src) { char *tmp = dest; @@ -69,7 +74,7 @@ extern __inline__ char *strcpy(char *dest, const char *src) return tmp; } -extern __inline__ size_t strlen(const char *s) +static __inline__ size_t strlen(const char *s) { size_t len; @@ -84,7 +89,7 @@ extern __inline__ size_t strlen(const char *s) return len; } -extern __inline__ char *strcat(char *dest, const char *src) +static __inline__ char *strcat(char *dest, const char *src) { char *tmp = dest; @@ -100,8 +105,13 @@ extern __inline__ char *strcat(char *dest, const char *src) return tmp; } +extern void *alloca(size_t); #endif /* __KERNEL__ */ #endif /* __S390_STRING_H_ */ + + + + diff --git a/include/asm-s390/system.h b/include/asm-s390/system.h index afced6af1..49ccb1a74 100644 --- a/include/asm-s390/system.h +++ b/include/asm-s390/system.h @@ -12,6 +12,7 @@ #define __ASM_SYSTEM_H #include <linux/config.h> +#include <asm/types.h> #ifdef __KERNEL__ #include <asm/lowcore.h> #endif @@ -40,7 +41,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) asm volatile ( " lhi 1,3\n" " nr 1,%0\n" /* isolate last 2 bits */ - " xr 1,%0\n" /* align ptr */ + " xr %0,1\n" /* align ptr */ " bras 2,0f\n" " icm 1,8,%1\n" /* for ptr&3 == 0 */ " stcm 0,8,%1\n" @@ -52,13 +53,13 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " stcm 0,1,%1\n" "0: sll 1,3\n" " la 2,0(1,2)\n" /* r2 points to an icm */ - " l 0,%1\n" /* get fullword */ + " l 0,0(%0)\n" /* get fullword */ "1: lr 1,0\n" /* cs loop */ " ex 0,0(2)\n" /* insert x */ - " cs 0,1,%1\n" + " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr) : "m" (x) + : "+a&" (ptr), "+m" (x) : : "memory", "0", "1", "2"); case 2: if(((__u32)ptr)&1) @@ -66,7 +67,7 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) asm volatile ( " lhi 1,2\n" " nr 1,%0\n" /* isolate bit 2^1 */ - " xr 1,%0\n" /* align ptr */ + " xr %0,1\n" /* align ptr */ " bras 2,0f\n" " icm 1,12,%1\n" /* for ptr&2 == 0 */ " stcm 0,12,%1\n" @@ -74,13 +75,13 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) " stcm 0,3,%1\n" "0: sll 1,2\n" " la 2,0(1,2)\n" /* r2 points to an icm */ - " l 0,%1\n" /* get fullword */ + " l 0,0(%0)\n" /* get fullword */ "1: lr 1,0\n" /* cs loop */ " ex 0,0(2)\n" /* insert x */ - " cs 0,1,%1\n" + " cs 0,1,0(%0)\n" " jl 1b\n" " ex 0,4(2)" /* store *ptr to x */ - : "+a&" (ptr) : "m" (x) + : "+a&" (ptr), "+m" (x) : : "memory", "0", "1", "2"); break; case 4: @@ -115,6 +116,12 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) #define mb() eieio() #define rmb() eieio() #define wmb() eieio() +#define smp_mb() mb() +#define smp_rmb() rmb() +#define smp_wmb() wmb() +#define smp_mb__before_clear_bit() smp_mb() +#define smp_mb__after_clear_bit() smp_mb() + #define set_mb(var, value) do { var = value; mb(); } while (0) #define set_wmb(var, value) do { var = value; wmb(); } while (0) @@ -139,6 +146,27 @@ static inline unsigned long __xchg(unsigned long x, void * ptr, int size) #define __restore_flags(x) \ __asm__ __volatile__("ssm %0" : : "m" (x) : "memory") +#define __load_psw(psw) \ + __asm__ __volatile__("lpsw %0" : : "m" (psw)); + +#define __ctl_load(array, low, high) ({ \ + __asm__ __volatile__ ( \ + " la 1,%0\n" \ + " bras 2,0f\n" \ + " lctl 0,0,0(1)\n" \ + "0: ex %1,0(2)" \ + : : "m" (array), "a" (((low)<<4)+(high)) : "1", "2" ); \ + }) + +#define __ctl_store(array, low, high) ({ \ + __asm__ __volatile__ ( \ + " la 1,%0\n" \ + " bras 2,0f\n" \ + " stctl 0,0,0(1)\n" \ + "0: ex %1,0(2)" \ + : "=m" (array) : "a" (((low)<<4)+(high)): "1", "2" ); \ + }) + #define __ctl_set_bit(cr, bit) ({ \ __u8 dummy[16]; \ __asm__ __volatile__ ( \ @@ -220,7 +248,6 @@ extern int save_fp_regs1(s390_fp_regs *fpregs); extern void save_fp_regs(s390_fp_regs *fpregs); extern int restore_fp_regs1(s390_fp_regs *fpregs); extern void restore_fp_regs(s390_fp_regs *fpregs); -extern void show_crashed_task_info(void); #endif #endif diff --git a/include/asm-s390/termios.h b/include/asm-s390/termios.h index 86415c0a2..30defbf1d 100644 --- a/include/asm-s390/termios.h +++ b/include/asm-s390/termios.h @@ -60,7 +60,7 @@ struct termio { #define N_MASC 8 /* Reserved for Mobitex module <kaz@cafe.net> */ #define N_R3964 9 /* Reserved for Simatic R3964 module */ #define N_PROFIBUS_FDL 10 /* Reserved for Profibus <Dave@mvhi.com> */ -#define N_IRDA 11 /* Linux IR - http://www.cs.uit.no/~dagb/irda/irda.html */ +#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */ #define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */ #define N_HDLC 13 /* synchronous HDLC */ @@ -77,18 +77,19 @@ struct termio { /* * Translate a "termio" structure into a "termios". Ugh. */ -#define SET_LOW_TERMIOS_BITS(termios, termio, x) { \ - unsigned short __tmp; \ - get_user(__tmp,&(termio)->x); \ - *(unsigned short *) &(termios)->x = __tmp; \ -} #define user_termio_to_kernel_termios(termios, termio) \ ({ \ - SET_LOW_TERMIOS_BITS(termios, termio, c_iflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_oflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_cflag); \ - SET_LOW_TERMIOS_BITS(termios, termio, c_lflag); \ + unsigned short tmp; \ + get_user(tmp, &(termio)->c_iflag); \ + (termios)->c_iflag = (0xffff0000 & ((termios)->c_iflag)) | tmp; \ + get_user(tmp, &(termio)->c_oflag); \ + (termios)->c_oflag = (0xffff0000 & ((termios)->c_oflag)) | tmp; \ + get_user(tmp, &(termio)->c_cflag); \ + (termios)->c_cflag = (0xffff0000 & ((termios)->c_cflag)) | tmp; \ + get_user(tmp, &(termio)->c_lflag); \ + (termios)->c_lflag = (0xffff0000 & ((termios)->c_lflag)) | tmp; \ + get_user((termios)->c_line, &(termio)->c_line); \ copy_from_user((termios)->c_cc, (termio)->c_cc, NCC); \ }) diff --git a/include/asm-s390/todclk.h b/include/asm-s390/todclk.h new file mode 100644 index 000000000..92a27a9d4 --- /dev/null +++ b/include/asm-s390/todclk.h @@ -0,0 +1,19 @@ +/* + * File...........: linux/include/asm/todclk.h + * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> + * Bugreports.to..: <Linux390@de.ibm.com> + * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 + * + * History of changes (starts July 2000) + */ + +#ifndef __ASM_TODCLK_H +#define __ASM_TODCLK_H + +#define TOD_uSEC (0x1000ULL) +#define TOD_mSEC (1000 * TOD_uSEC) +#define TOD_SEC (1000 * TOD_mSEC) +#define TOD_MIN (60 * TOD_SEC) +#define TOD_HOUR (60 * TOD_MIN) + +#endif diff --git a/include/asm-s390/uaccess.h b/include/asm-s390/uaccess.h index a19cfa29f..3bcf7bbed 100644 --- a/include/asm-s390/uaccess.h +++ b/include/asm-s390/uaccess.h @@ -84,15 +84,14 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr) { int err; - __asm__ __volatile__ ( " iac 1\n" - " sr %1,%1\n" + __asm__ __volatile__ ( " sr %1,%1\n" " la 4,%0\n" " sacf 512\n" "0: st %2,0(4)\n" - " sacf 0(1)\n" + " sacf 0\n" "1:\n" ".section .fixup,\"ax\"\n" - "2: sacf 0(1)\n" + "2: sacf 0\n" " lhi %1,%h3\n" " bras 4,3f\n" " .long 1b\n" @@ -105,7 +104,7 @@ extern inline int __put_user_asm_4(__u32 x, void *ptr) ".previous" : "=m" (*((__u32*) ptr)) , "=&d" (err) : "d" (x), "K" (-EFAULT) - : "1", "4" ); + : "4" ); return err; } @@ -113,15 +112,14 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr) { int err; - __asm__ __volatile__ ( " iac 1\n" - " sr %1,%1\n" + __asm__ __volatile__ ( " sr %1,%1\n" " la 4,%0\n" " sacf 512\n" "0: sth %2,0(4)\n" - " sacf 0(1)\n" + " sacf 0\n" "1:\n" ".section .fixup,\"ax\"\n" - "2: sacf 0(1)\n" + "2: sacf 0\n" " lhi %1,%h3\n" " bras 4,3f\n" " .long 1b\n" @@ -134,7 +132,7 @@ extern inline int __put_user_asm_2(__u16 x, void *ptr) ".previous" : "=m" (*((__u16*) ptr)) , "=&d" (err) : "d" (x), "K" (-EFAULT) - : "1", "4" ); + : "4" ); return err; } @@ -142,15 +140,14 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr) { int err; - __asm__ __volatile__ ( " iac 1\n" - " sr %1,%1\n" + __asm__ __volatile__ ( " sr %1,%1\n" " la 4,%0\n" " sacf 512\n" "0: stc %2,0(4)\n" - " sacf 0(1)\n" + " sacf 0\n" "1:\n" ".section .fixup,\"ax\"\n" - "2: sacf 0(1)\n" + "2: sacf 0\n" " lhi %1,%h3\n" " bras 4,3f\n" " .long 1b\n" @@ -163,7 +160,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr) ".previous" : "=m" (*((__u8*) ptr)) , "=&d" (err) : "d" (x), "K" (-EFAULT) - : "1", "4" ); + : "4" ); return err; } @@ -176,13 +173,13 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr) int __pu_err; \ switch (sizeof (*(ptr))) { \ case 1: \ - __pu_err = __put_user_asm_1((__u8)(__u32)x,ptr);\ + __pu_err = __put_user_asm_1((__u8)(__u32)x,(ptr));\ break; \ case 2: \ - __pu_err = __put_user_asm_2((__u16)(__u32)x,ptr);\ + __pu_err = __put_user_asm_2((__u16)(__u32)x,(ptr));\ break; \ case 4: \ - __pu_err = __put_user_asm_4((__u32) x,ptr);\ + __pu_err = __put_user_asm_4((__u32) x,(ptr));\ break; \ default: \ __pu_err = __put_user_bad(); \ @@ -195,7 +192,7 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr) ({ \ long __pu_err = -EFAULT; \ __typeof__(*(ptr)) *__pu_addr = (ptr); \ - __typeof__(x) __x = (x); \ + __typeof__(*(ptr)) __x = (x); \ if (__access_ok((long)__pu_addr,sizeof(*(ptr)))) { \ __pu_err = 0; \ __put_user((__x), (__pu_addr)); \ @@ -206,83 +203,80 @@ extern inline int __put_user_asm_1(__u8 x, void *ptr) extern int __put_user_bad(void); -#define __get_user_asm_4(x, ptr, err) \ -({ \ - __asm__ __volatile__ ( " iac 1\n" \ - " sr %1,%1\n" \ - " la 4,%2\n" \ - " sacf 512\n" \ - "0: l %0,0(4)\n" \ - " sacf 0(1)\n" \ - "1:\n" \ - ".section .fixup,\"ax\"\n" \ - "2: sacf 0(1)\n" \ - " lhi %1,%h3\n" \ - " bras 4,3f\n" \ - " .long 1b\n" \ - "3: l 4,0(4)\n" \ - " br 4\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 0b,2b\n" \ - ".previous" \ - : "=d" (x) , "=&d" (err) \ - : "m" (*(__u32*) ptr), "K" (-EFAULT) \ - : "1", "4" ); \ +#define __get_user_asm_4(x, ptr, err) \ +({ \ + __asm__ __volatile__ ( " sr %1,%1\n" \ + " la 4,%2\n" \ + " sacf 512\n" \ + "0: l %0,0(4)\n" \ + " sacf 0\n" \ + "1:\n" \ + ".section .fixup,\"ax\"\n" \ + "2: sacf 0\n" \ + " lhi %1,%h3\n" \ + " bras 4,3f\n" \ + " .long 1b\n" \ + "3: l 4,0(4)\n" \ + " br 4\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,2b\n" \ + ".previous" \ + : "=d" (x) , "=&d" (err) \ + : "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \ + : "4" ); \ }) -#define __get_user_asm_2(x, ptr, err) \ -({ \ - __asm__ __volatile__ ( " iac 1\n" \ - " sr %1,%1\n" \ - " la 4,%2\n" \ - " sacf 512\n" \ - "0: lh %0,0(4)\n" \ - " sacf 0(1)\n" \ - "1:\n" \ - ".section .fixup,\"ax\"\n" \ - "2: sacf 0(1)\n" \ - " lhi %1,%h3\n" \ - " bras 4,3f\n" \ - " .long 1b\n" \ - "3: l 4,0(4)\n" \ - " br 4\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 0b,2b\n" \ - ".previous" \ - : "=d" (x) , "=&d" (err) \ - : "m" (*(__u16*) ptr), "K" (-EFAULT) \ - : "1", "4" ); \ +#define __get_user_asm_2(x, ptr, err) \ +({ \ + __asm__ __volatile__ ( " sr %1,%1\n" \ + " la 4,%2\n" \ + " sacf 512\n" \ + "0: lh %0,0(4)\n" \ + " sacf 0\n" \ + "1:\n" \ + ".section .fixup,\"ax\"\n" \ + "2: sacf 0\n" \ + " lhi %1,%h3\n" \ + " bras 4,3f\n" \ + " .long 1b\n" \ + "3: l 4,0(4)\n" \ + " br 4\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,2b\n" \ + ".previous" \ + : "=d" (x) , "=&d" (err) \ + : "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \ + : "4" ); \ }) -#define __get_user_asm_1(x, ptr, err) \ -({ \ - __asm__ __volatile__ ( " iac 1\n" \ - " sr %1,%1\n" \ - " la 4,%2\n" \ - " sr %0,%0\n" \ - " sacf 512\n" \ - "0: ic %0,0(4)\n" \ - " sacf 0(1)\n" \ - "1:\n" \ - ".section .fixup,\"ax\"\n" \ - "2: sacf 0(1)\n" \ - " lhi %1,%h3\n" \ - " bras 4,3f\n" \ - " .long 1b\n" \ - "3: l 4,0(4)\n" \ - " br 4\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 0b,2b\n" \ - ".previous" \ - : "=d" (x) , "=&d" (err) \ - : "m" (*(__u8*) ptr), "K" (-EFAULT) \ - : "1", "4" ); \ +#define __get_user_asm_1(x, ptr, err) \ +({ \ + __asm__ __volatile__ ( " sr %1,%1\n" \ + " la 4,%2\n" \ + " sr %0,%0\n" \ + " sacf 512\n" \ + "0: ic %0,0(4)\n" \ + " sacf 0\n" \ + "1:\n" \ + ".section .fixup,\"ax\"\n" \ + "2: sacf 0\n" \ + " lhi %1,%h3\n" \ + " bras 4,3f\n" \ + " .long 1b\n" \ + "3: l 4,0(4)\n" \ + " br 4\n" \ + ".previous\n" \ + ".section __ex_table,\"a\"\n" \ + " .align 4\n" \ + " .long 0b,2b\n" \ + ".previous" \ + : "=d" (x) , "=&d" (err) \ + : "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \ + : "4" ); \ }) #define __get_user(x, ptr) \ @@ -310,7 +304,7 @@ extern int __put_user_bad(void); ({ \ long __gu_err = -EFAULT; \ __typeof__(ptr) __gu_addr = (ptr); \ - __typeof__(x) __x; \ + __typeof__(*(ptr)) __x; \ if (__access_ok((long)__gu_addr,sizeof(*(ptr)))) { \ __gu_err = 0; \ __get_user((__x), (__gu_addr)); \ @@ -327,26 +321,28 @@ extern int __get_user_bad(void); * access register are set up, that 4 points to secondary (user) , 2 to primary (kernel) */ +asmlinkage void __copy_from_user_fixup(void /* special calling convention */); +asmlinkage void __copy_to_user_fixup(void /* special calling convention */); + extern inline unsigned long __copy_to_user_asm(void* to, const void* from, long n) { - __asm__ __volatile__ ( " iac 1\n" - " lr 2,%2\n" + __asm__ __volatile__ ( " lr 2,%2\n" " lr 4,%1\n" " lr 3,%0\n" " lr 5,3\n" " sacf 512\n" "0: mvcle 4,2,0\n" " jo 0b\n" - "1: sacf 0(1)\n" + " sacf 0\n" " lr %0,3\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 0b,1b\n" + " .long 0b,__copy_to_user_fixup\n" ".previous" : "+&d" (n) : "d" (to), "d" (from) - : "1", "2", "3", "4", "5" ); + : "2", "3", "4", "5" ); return n; } @@ -370,22 +366,21 @@ __copy_to_user_asm(void* to, const void* from, long n) extern inline unsigned long __copy_from_user_asm(void* to, const void* from, long n) { - __asm__ __volatile__ ( " iac 1\n" - " lr 2,%1\n" + __asm__ __volatile__ ( " lr 2,%1\n" " lr 4,%2\n" " lr 3,%0\n" " lr 5,3\n" " sacf 512\n" "0: mvcle 2,4,0\n" " jo 0b\n" - "1: sacf 0(1)\n" + " sacf 0\n" " lr %0,3\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 0b,1b\n" + " .long 0b,__copy_from_user_fixup\n" ".previous" : "+&d" (n) : "d" (to), "d" (from) - : "1", "2", "3", "4", "5" ); + : "2", "3", "4", "5" ); return n; } @@ -412,11 +407,10 @@ __copy_from_user_asm(void* to, const void* from, long n) */ static inline long -strncpy_from_user(char *dst, const char *src, long count) +__strncpy_from_user(char *dst, const char *src, long count) { int len; - __asm__ __volatile__ ( " iac 1\n" - " slr %0,%0\n" + __asm__ __volatile__ ( " slr %0,%0\n" " lr 2,%1\n" " lr 4,%2\n" " slr 3,3\n" @@ -428,7 +422,7 @@ strncpy_from_user(char *dst, const char *src, long count) " ahi %0,1\n" " clr %0,%3\n" " jl 0b\n" - "2: sacf 0(1)\n" + "2: sacf 0\n" ".section .fixup,\"ax\"\n" "3: lhi %0,%h4\n" " basr 3,0\n" @@ -444,10 +438,20 @@ strncpy_from_user(char *dst, const char *src, long count) : "=&a" (len) : "a" (dst), "d" (src), "d" (count), "K" (-EFAULT) - : "1", "2", "3", "4", "memory" ); + : "2", "3", "4", "memory" ); return len; } +static inline long +strncpy_from_user(char *dst, const char *src, long count) +{ + long res = -EFAULT; + if (access_ok(VERIFY_READ, src, 1)) + res = __strncpy_from_user(dst, src, count); + return res; +} + + /* * Return the size of a string (including the ending 0) * @@ -456,8 +460,7 @@ strncpy_from_user(char *dst, const char *src, long count) static inline unsigned long strnlen_user(const char * src, unsigned long n) { - __asm__ __volatile__ (" iac 1\n" - " alr %0,%1\n" + __asm__ __volatile__ (" alr %0,%1\n" " slr 0,0\n" " lr 4,%1\n" " sacf 512\n" @@ -465,10 +468,10 @@ strnlen_user(const char * src, unsigned long n) " jo 0b\n" " slr %0,%1\n" " ahi %0,1\n" - " sacf 0(1)\n" + " sacf 0\n" "1:\n" ".section .fixup,\"ax\"\n" - "2: sacf 0(1)\n" + "2: sacf 0\n" " slr %0,%0\n" " bras 4,3f\n" " .long 1b\n" @@ -480,7 +483,7 @@ strnlen_user(const char * src, unsigned long n) " .long 0b,2b\n" ".previous" : "+&a" (n) : "d" (src) - : "cc", "0", "1", "4" ); + : "cc", "0", "4" ); return n; } #define strlen_user(str) strnlen_user(str, ~0UL) @@ -490,26 +493,45 @@ strnlen_user(const char * src, unsigned long n) */ static inline unsigned long -clear_user(void *to, unsigned long n) +__clear_user(void *to, unsigned long n) { - __asm__ __volatile__ ( " iac 1\n" - " sacf 512\n" + __asm__ __volatile__ ( " sacf 512\n" " lr 4,%1\n" " lr 5,%0\n" " sr 2,2\n" " sr 3,3\n" "0: mvcle 4,2,0\n" " jo 0b\n" - "1: sacf 0(1)\n" - " lr %0,3\n" + " sacf 0\n" + "1: lr %0,3\n" + ".section .fixup,\"ax\"\n" + "2: lhi 5,-4096\n" + " n 5,0x90\n" + " sr 5,4\n" + " mvcle 4,2,0\n" + " sacf 0\n" + " basr 4,0\n" + " l 4,3f-.(4)\n" + " br 4\n" + "3: .long 1b\n" + ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" - " .long 0b,1b\n" + " .long 0b,2b\n" ".previous" : "+&a" (n) : "a" (to) - : "cc", "1", "2", "3", "4", "5" ); + : "cc", "2", "3", "4", "5" ); + return n; +} + +static inline unsigned long +clear_user(void *to, unsigned long n) +{ + if (access_ok(VERIFY_WRITE, to, n)) + n = __clear_user(to, n); return n; } + #endif /* _S390_UACCESS_H */ diff --git a/include/asm-s390/ucontext.h b/include/asm-s390/ucontext.h index cf7c431f1..d4e39ae77 100644 --- a/include/asm-s390/ucontext.h +++ b/include/asm-s390/ucontext.h @@ -13,8 +13,10 @@ struct ucontext { unsigned long uc_flags; struct ucontext *uc_link; stack_t uc_stack; - struct sigcontext uc_mcontext; sigset_t uc_sigmask; /* mask last for extensibility */ + struct sigcontext *sc; /* Added for pthread support */ }; + + #endif /* !_ASM_S390_UCONTEXT_H */ diff --git a/include/asm-s390/unistd.h b/include/asm-s390/unistd.h index e7da084b0..b223e0490 100644 --- a/include/asm-s390/unistd.h +++ b/include/asm-s390/unistd.h @@ -222,7 +222,7 @@ do { \ return (type) (res); \ } while (0) -#define _svc_clobber "cc", "memory" +#define _svc_clobber "2", "cc", "memory" #define _syscall0(type,name) \ type name(void) { \ @@ -359,7 +359,6 @@ static inline _syscall1(int,_exit,int,exitcode) static inline _syscall1(int,delete_module,const char *,name) static inline _syscall2(long,stat,char *,filename,struct stat *,statbuf) -extern int sys_wait4(int, int *, int, struct rusage *); static inline pid_t waitpid(int pid, int * wait_stat, int flags) { return sys_wait4(pid, wait_stat, flags, NULL); |