unaligned-sh4a.h 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #ifndef __ASM_SH_UNALIGNED_SH4A_H
  2. #define __ASM_SH_UNALIGNED_SH4A_H
  3. /*
  4. * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only.
  5. * Support for 64-bit accesses are done through shifting and masking
  6. * relative to the endianness. Unaligned stores are not supported by the
  7. * instruction encoding, so these continue to use the packed
  8. * struct.
  9. *
  10. * The same note as with the movli.l/movco.l pair applies here, as long
  11. * as the load is gauranteed to be inlined, nothing else will hook in to
  12. * r0 and we get the return value for free.
  13. *
  14. * NOTE: Due to the fact we require r0 encoding, care should be taken to
  15. * avoid mixing these heavily with other r0 consumers, such as the atomic
  16. * ops. Failure to adhere to this can result in the compiler running out
  17. * of spill registers and blowing up when building at low optimization
  18. * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777.
  19. */
  20. #include <linux/types.h>
  21. #include <asm/byteorder.h>
  22. static __always_inline u32 __get_unaligned_cpu32(const u8 *p)
  23. {
  24. unsigned long unaligned;
  25. __asm__ __volatile__ (
  26. "movua.l @%1, %0\n\t"
  27. : "=z" (unaligned)
  28. : "r" (p)
  29. );
  30. return unaligned;
  31. }
  32. struct __una_u16 { u16 x __attribute__((packed)); };
  33. struct __una_u32 { u32 x __attribute__((packed)); };
  34. struct __una_u64 { u64 x __attribute__((packed)); };
  35. static inline u16 __get_unaligned_cpu16(const u8 *p)
  36. {
  37. #ifdef __LITTLE_ENDIAN
  38. return p[0] | p[1] << 8;
  39. #else
  40. return p[0] << 8 | p[1];
  41. #endif
  42. }
  43. /*
  44. * Even though movua.l supports auto-increment on the read side, it can
  45. * only store to r0 due to instruction encoding constraints, so just let
  46. * the compiler sort it out on its own.
  47. */
  48. static inline u64 __get_unaligned_cpu64(const u8 *p)
  49. {
  50. #ifdef __LITTLE_ENDIAN
  51. return (u64)__get_unaligned_cpu32(p + 4) << 32 |
  52. __get_unaligned_cpu32(p);
  53. #else
  54. return (u64)__get_unaligned_cpu32(p) << 32 |
  55. __get_unaligned_cpu32(p + 4);
  56. #endif
  57. }
  58. static inline u16 get_unaligned_le16(const void *p)
  59. {
  60. return le16_to_cpu(__get_unaligned_cpu16(p));
  61. }
  62. static inline u32 get_unaligned_le32(const void *p)
  63. {
  64. return le32_to_cpu(__get_unaligned_cpu32(p));
  65. }
  66. static inline u64 get_unaligned_le64(const void *p)
  67. {
  68. return le64_to_cpu(__get_unaligned_cpu64(p));
  69. }
  70. static inline u16 get_unaligned_be16(const void *p)
  71. {
  72. return be16_to_cpu(__get_unaligned_cpu16(p));
  73. }
  74. static inline u32 get_unaligned_be32(const void *p)
  75. {
  76. return be32_to_cpu(__get_unaligned_cpu32(p));
  77. }
  78. static inline u64 get_unaligned_be64(const void *p)
  79. {
  80. return be64_to_cpu(__get_unaligned_cpu64(p));
  81. }
  82. static inline void __put_le16_noalign(u8 *p, u16 val)
  83. {
  84. *p++ = val;
  85. *p++ = val >> 8;
  86. }
  87. static inline void __put_le32_noalign(u8 *p, u32 val)
  88. {
  89. __put_le16_noalign(p, val);
  90. __put_le16_noalign(p + 2, val >> 16);
  91. }
  92. static inline void __put_le64_noalign(u8 *p, u64 val)
  93. {
  94. __put_le32_noalign(p, val);
  95. __put_le32_noalign(p + 4, val >> 32);
  96. }
  97. static inline void __put_be16_noalign(u8 *p, u16 val)
  98. {
  99. *p++ = val >> 8;
  100. *p++ = val;
  101. }
  102. static inline void __put_be32_noalign(u8 *p, u32 val)
  103. {
  104. __put_be16_noalign(p, val >> 16);
  105. __put_be16_noalign(p + 2, val);
  106. }
  107. static inline void __put_be64_noalign(u8 *p, u64 val)
  108. {
  109. __put_be32_noalign(p, val >> 32);
  110. __put_be32_noalign(p + 4, val);
  111. }
  112. static inline void put_unaligned_le16(u16 val, void *p)
  113. {
  114. #ifdef __LITTLE_ENDIAN
  115. ((struct __una_u16 *)p)->x = val;
  116. #else
  117. __put_le16_noalign(p, val);
  118. #endif
  119. }
  120. static inline void put_unaligned_le32(u32 val, void *p)
  121. {
  122. #ifdef __LITTLE_ENDIAN
  123. ((struct __una_u32 *)p)->x = val;
  124. #else
  125. __put_le32_noalign(p, val);
  126. #endif
  127. }
  128. static inline void put_unaligned_le64(u64 val, void *p)
  129. {
  130. #ifdef __LITTLE_ENDIAN
  131. ((struct __una_u64 *)p)->x = val;
  132. #else
  133. __put_le64_noalign(p, val);
  134. #endif
  135. }
  136. static inline void put_unaligned_be16(u16 val, void *p)
  137. {
  138. #ifdef __BIG_ENDIAN
  139. ((struct __una_u16 *)p)->x = val;
  140. #else
  141. __put_be16_noalign(p, val);
  142. #endif
  143. }
  144. static inline void put_unaligned_be32(u32 val, void *p)
  145. {
  146. #ifdef __BIG_ENDIAN
  147. ((struct __una_u32 *)p)->x = val;
  148. #else
  149. __put_be32_noalign(p, val);
  150. #endif
  151. }
  152. static inline void put_unaligned_be64(u64 val, void *p)
  153. {
  154. #ifdef __BIG_ENDIAN
  155. ((struct __una_u64 *)p)->x = val;
  156. #else
  157. __put_be64_noalign(p, val);
  158. #endif
  159. }
  160. /*
  161. * Cause a link-time error if we try an unaligned access other than
  162. * 1,2,4 or 8 bytes long
  163. */
  164. extern void __bad_unaligned_access_size(void);
  165. #define __get_unaligned_le(ptr) ((__force typeof(*(ptr)))({ \
  166. __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
  167. __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_le16((ptr)), \
  168. __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_le32((ptr)), \
  169. __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_le64((ptr)), \
  170. __bad_unaligned_access_size())))); \
  171. }))
  172. #define __get_unaligned_be(ptr) ((__force typeof(*(ptr)))({ \
  173. __builtin_choose_expr(sizeof(*(ptr)) == 1, *(ptr), \
  174. __builtin_choose_expr(sizeof(*(ptr)) == 2, get_unaligned_be16((ptr)), \
  175. __builtin_choose_expr(sizeof(*(ptr)) == 4, get_unaligned_be32((ptr)), \
  176. __builtin_choose_expr(sizeof(*(ptr)) == 8, get_unaligned_be64((ptr)), \
  177. __bad_unaligned_access_size())))); \
  178. }))
  179. #define __put_unaligned_le(val, ptr) ({ \
  180. void *__gu_p = (ptr); \
  181. switch (sizeof(*(ptr))) { \
  182. case 1: \
  183. *(u8 *)__gu_p = (__force u8)(val); \
  184. break; \
  185. case 2: \
  186. put_unaligned_le16((__force u16)(val), __gu_p); \
  187. break; \
  188. case 4: \
  189. put_unaligned_le32((__force u32)(val), __gu_p); \
  190. break; \
  191. case 8: \
  192. put_unaligned_le64((__force u64)(val), __gu_p); \
  193. break; \
  194. default: \
  195. __bad_unaligned_access_size(); \
  196. break; \
  197. } \
  198. (void)0; })
  199. #define __put_unaligned_be(val, ptr) ({ \
  200. void *__gu_p = (ptr); \
  201. switch (sizeof(*(ptr))) { \
  202. case 1: \
  203. *(u8 *)__gu_p = (__force u8)(val); \
  204. break; \
  205. case 2: \
  206. put_unaligned_be16((__force u16)(val), __gu_p); \
  207. break; \
  208. case 4: \
  209. put_unaligned_be32((__force u32)(val), __gu_p); \
  210. break; \
  211. case 8: \
  212. put_unaligned_be64((__force u64)(val), __gu_p); \
  213. break; \
  214. default: \
  215. __bad_unaligned_access_size(); \
  216. break; \
  217. } \
  218. (void)0; })
  219. #ifdef __LITTLE_ENDIAN
  220. # define get_unaligned __get_unaligned_le
  221. # define put_unaligned __put_unaligned_le
  222. #else
  223. # define get_unaligned __get_unaligned_be
  224. # define put_unaligned __put_unaligned_be
  225. #endif
  226. #endif /* __ASM_SH_UNALIGNED_SH4A_H */