make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / include / asm-mips64 / unaligned.h
1 /*
2  * This file is subject to the terms and conditions of the GNU General Public
3  * License.  See the file "COPYING" in the main directory of this archive
4  * for more details.
5  *
6  * Copyright (C) 1996, 1999, 2000, 2001 by Ralf Baechle
7  * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
8  */
9 #ifndef _ASM_UNALIGNED_H
10 #define _ASM_UNALIGNED_H
11
12 extern void __get_unaligned_bad_length(void);
13 extern void __put_unaligned_bad_length(void);
14
15 /*
16  * Load quad unaligned.
17  */
18 static inline unsigned long __ldq_u(const unsigned long * __addr)
19 {
20         unsigned long __res;
21
22         __asm__("uld\t%0,%1"
23                 : "=&r" (__res)
24                 : "m" (*__addr));
25
26         return __res;
27 }
28
29 /*
30  * Load long unaligned.
31  */
32 static inline unsigned long __ldl_u(const unsigned int * __addr)
33 {
34         unsigned long __res;
35
36         __asm__("ulw\t%0,%1"
37                 : "=&r" (__res)
38                 : "m" (*__addr));
39
40         return __res;
41 }
42
43 /*
44  * Load word unaligned.
45  */
46 static inline unsigned long __ldw_u(const unsigned short * __addr)
47 {
48         unsigned long __res;
49
50         __asm__("ulh\t%0,%1"
51                 : "=&r" (__res)
52                 : "m" (*__addr));
53
54         return __res;
55 }
56
57 /*
58  * Store quad ununaligned.
59  */
60 static inline void __stq_u(unsigned long __val, unsigned long * __addr)
61 {
62         __asm__("usd\t%1, %0"
63                 : "=m" (*__addr)
64                 : "r" (__val));
65 }
66
67 /*
68  * Store long ununaligned.
69  */
70 static inline void __stl_u(unsigned long __val, unsigned int * __addr)
71 {
72         __asm__("usw\t%1, %0"
73                 : "=m" (*__addr)
74                 : "r" (__val));
75 }
76
77 /*
78  * Store word ununaligned.
79  */
80 static inline void __stw_u(unsigned long __val, unsigned short * __addr)
81 {
82         __asm__("ush\t%1, %0"
83                 : "=m" (*__addr)
84                 : "r" (__val));
85 }
86
87 /*
88  * get_unaligned - get value from possibly mis-aligned location
89  * @ptr: pointer to value
90  *
91  * This macro should be used for accessing values larger in size than
92  * single bytes at locations that are expected to be improperly aligned,
93  * e.g. retrieving a u16 value from a location not u16-aligned.
94  *
95  * Note that unaligned accesses can be very expensive on some architectures.
96  */
97 #define get_unaligned(ptr)                                              \
98 ({                                                                      \
99         __typeof__(*(ptr)) __val;                                       \
100                                                                         \
101         switch (sizeof(*(ptr))) {                                       \
102         case 1:                                                         \
103                 __val = *(const unsigned char *)(ptr);                  \
104                 break;                                                  \
105         case 2:                                                         \
106                 __val = __ldw_u((const unsigned short *)(ptr));         \
107                 break;                                                  \
108         case 4:                                                         \
109                 __val = __ldl_u((const unsigned int *)(ptr));           \
110                 break;                                                  \
111         case 8:                                                         \
112                 __val = __ldq_u((const unsigned long *)(ptr));          \
113                 break;                                                  \
114         default:                                                        \
115                 __get_unaligned_bad_length();                           \
116                 break;                                                  \
117         }                                                               \
118                                                                         \
119         __val;                                                          \
120 })
121
122 /*
123  * put_unaligned - put value to a possibly mis-aligned location
124  * @val: value to place
125  * @ptr: pointer to location
126  *
127  * This macro should be used for placing values larger in size than
128  * single bytes at locations that are expected to be improperly aligned,
129  * e.g. writing a u16 value to a location not u16-aligned.
130  *
131  * Note that unaligned accesses can be very expensive on some architectures.
132  */
133 #define put_unaligned(val,ptr)                                          \
134 do {                                                                    \
135         switch (sizeof(*(ptr))) {                                       \
136         case 1:                                                         \
137                 *(unsigned char *)(ptr) = (val);                        \
138                 break;                                                  \
139         case 2:                                                         \
140                 __stw_u((val), (unsigned short *)(ptr));                \
141                 break;                                                  \
142         case 4:                                                         \
143                 __stl_u((val), (unsigned int *)(ptr));                  \
144                 break;                                                  \
145         case 8:                                                         \
146                 __stq_u((val), (unsigned long long *)(ptr));            \
147                 break;                                                  \
148         default:                                                        \
149                 __put_unaligned_bad_length();                           \
150                 break;                                                  \
151         }                                                               \
152 } while(0)
153
154 #endif /* _ASM_UNALIGNED_H */