mn10300: add the MN10300/AM33 architecture to the kernel
[pandora-kernel.git] / include / asm-mn10300 / unaligned.h
1 /* MN10300 Unaligned memory access handling
2  *
3  * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
4  * Written by David Howells (dhowells@redhat.com)
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public Licence
8  * as published by the Free Software Foundation; either version
9  * 2 of the Licence, or (at your option) any later version.
10  */
11 #ifndef _ASM_UNALIGNED_H
12 #define _ASM_UNALIGNED_H
13
14 #include <asm/types.h>
15
16 #if 0
17 extern int __bug_unaligned_x(void *ptr);
18
19 /*
20  * What is the most efficient way of loading/storing an unaligned value?
21  *
22  * That is the subject of this file.  Efficiency here is defined as
23  * minimum code size with minimum register usage for the common cases.
24  * It is currently not believed that long longs are common, so we
25  * trade efficiency for the chars, shorts and longs against the long
26  * longs.
27  *
28  * Current stats with gcc 2.7.2.2 for these functions:
29  *
30  *      ptrsize get:    code    regs    put:    code    regs
31  *      1               1       1               1       2
32  *      2               3       2               3       2
33  *      4               7       3               7       3
34  *      8               20      6               16      6
35  *
36  * gcc 2.95.1 seems to code differently:
37  *
38  *      ptrsize get:    code    regs    put:    code    regs
39  *      1               1       1               1       2
40  *      2               3       2               3       2
41  *      4               7       4               7       4
42  *      8               19      8               15      6
43  *
44  * which may or may not be more efficient (depending upon whether
45  * you can afford the extra registers).  Hopefully the gcc 2.95
46  * is inteligent enough to decide if it is better to use the
47  * extra register, but evidence so far seems to suggest otherwise.
48  *
49  * Unfortunately, gcc is not able to optimise the high word
50  * out of long long >> 32, or the low word from long long << 32
51  */
52
53 #define __get_unaligned_2(__p)                                  \
54         (__p[0] | __p[1] << 8)
55
56 #define __get_unaligned_4(__p)                                  \
57         (__p[0] | __p[1] << 8 | __p[2] << 16 | __p[3] << 24)
58
59 #define get_unaligned(ptr)                                      \
60 ({                                                              \
61         unsigned int __v1, __v2;                                \
62         __typeof__(*(ptr)) __v;                                 \
63         __u8 *__p = (__u8 *)(ptr);                              \
64                                                                 \
65         switch (sizeof(*(ptr))) {                               \
66         case 1: __v = *(ptr);                   break;          \
67         case 2: __v = __get_unaligned_2(__p);   break;          \
68         case 4: __v = __get_unaligned_4(__p);   break;          \
69         case 8:                                                 \
70                 __v2 = __get_unaligned_4((__p+4));              \
71                 __v1 = __get_unaligned_4(__p);                  \
72                 __v = ((unsigned long long)__v2 << 32 | __v1);  \
73                 break;                                          \
74         default: __v = __bug_unaligned_x(__p);  break;          \
75         }                                                       \
76         __v;                                                    \
77 })
78
79
80 static inline void __put_unaligned_2(__u32 __v, register __u8 *__p)
81 {
82         *__p++ = __v;
83         *__p++ = __v >> 8;
84 }
85
86 static inline void __put_unaligned_4(__u32 __v, register __u8 *__p)
87 {
88         __put_unaligned_2(__v >> 16, __p + 2);
89         __put_unaligned_2(__v, __p);
90 }
91
92 static inline void __put_unaligned_8(const unsigned long long __v, __u8 *__p)
93 {
94         /*
95          * tradeoff: 8 bytes of stack for all unaligned puts (2
96          * instructions), or an extra register in the long long
97          * case - go for the extra register.
98          */
99         __put_unaligned_4(__v >> 32, __p + 4);
100         __put_unaligned_4(__v, __p);
101 }
102
103 /*
104  * Try to store an unaligned value as efficiently as possible.
105  */
106 #define put_unaligned(val, ptr)                                         \
107         ({                                                              \
108                 switch (sizeof(*(ptr))) {                               \
109                 case 1:                                                 \
110                         *(ptr) = (val);                                 \
111                         break;                                          \
112                 case 2:                                                 \
113                         __put_unaligned_2((val), (__u8 *)(ptr));        \
114                         break;                                          \
115                 case 4:                                                 \
116                         __put_unaligned_4((val), (__u8 *)(ptr));        \
117                         break;                                          \
118                 case 8:                                                 \
119                         __put_unaligned_8((val), (__u8 *)(ptr));        \
120                         break;                                          \
121                 default:                                                \
122                         __bug_unaligned_x(ptr);                         \
123                         break;                                          \
124                 }                                                       \
125                 (void) 0;                                               \
126         })
127
128
129 #else
130
131 #define get_unaligned(ptr) (*(ptr))
132 #define put_unaligned(val, ptr) ({ *(ptr) = (val); (void) 0; })
133
134 #endif
135
136 #endif