linux/arch/sh/include/asm/unaligned-sh4a.h
<<
>>
Prefs
   1#ifndef __ASM_SH_UNALIGNED_SH4A_H
   2#define __ASM_SH_UNALIGNED_SH4A_H
   3
   4/*
   5 * SH-4A has support for unaligned 32-bit loads, and 32-bit loads only.
   6 * Support for 64-bit accesses are done through shifting and masking
   7 * relative to the endianness. Unaligned stores are not supported by the
   8 * instruction encoding, so these continue to use the packed
   9 * struct.
  10 *
  11 * The same note as with the movli.l/movco.l pair applies here, as long
  12 * as the load is guaranteed to be inlined, nothing else will hook in to
  13 * r0 and we get the return value for free.
  14 *
  15 * NOTE: Due to the fact we require r0 encoding, care should be taken to
  16 * avoid mixing these heavily with other r0 consumers, such as the atomic
  17 * ops. Failure to adhere to this can result in the compiler running out
  18 * of spill registers and blowing up when building at low optimization
  19 * levels. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34777.
  20 */
  21#include <linux/unaligned/packed_struct.h>
  22#include <linux/types.h>
  23#include <asm/byteorder.h>
  24
  25static inline u16 sh4a_get_unaligned_cpu16(const u8 *p)
  26{
  27#ifdef __LITTLE_ENDIAN
  28        return p[0] | p[1] << 8;
  29#else
  30        return p[0] << 8 | p[1];
  31#endif
  32}
  33
  34static __always_inline u32 sh4a_get_unaligned_cpu32(const u8 *p)
  35{
  36        unsigned long unaligned;
  37
  38        __asm__ __volatile__ (
  39                "movua.l        @%1, %0\n\t"
  40                 : "=z" (unaligned)
  41                 : "r" (p)
  42        );
  43
  44        return unaligned;
  45}
  46
  47/*
  48 * Even though movua.l supports auto-increment on the read side, it can
  49 * only store to r0 due to instruction encoding constraints, so just let
  50 * the compiler sort it out on its own.
  51 */
  52static inline u64 sh4a_get_unaligned_cpu64(const u8 *p)
  53{
  54#ifdef __LITTLE_ENDIAN
  55        return (u64)sh4a_get_unaligned_cpu32(p + 4) << 32 |
  56                    sh4a_get_unaligned_cpu32(p);
  57#else
  58        return (u64)sh4a_get_unaligned_cpu32(p) << 32 |
  59                    sh4a_get_unaligned_cpu32(p + 4);
  60#endif
  61}
  62
  63static inline u16 get_unaligned_le16(const void *p)
  64{
  65        return le16_to_cpu(sh4a_get_unaligned_cpu16(p));
  66}
  67
  68static inline u32 get_unaligned_le32(const void *p)
  69{
  70        return le32_to_cpu(sh4a_get_unaligned_cpu32(p));
  71}
  72
  73static inline u64 get_unaligned_le64(const void *p)
  74{
  75        return le64_to_cpu(sh4a_get_unaligned_cpu64(p));
  76}
  77
  78static inline u16 get_unaligned_be16(const void *p)
  79{
  80        return be16_to_cpu(sh4a_get_unaligned_cpu16(p));
  81}
  82
  83static inline u32 get_unaligned_be32(const void *p)
  84{
  85        return be32_to_cpu(sh4a_get_unaligned_cpu32(p));
  86}
  87
  88static inline u64 get_unaligned_be64(const void *p)
  89{
  90        return be64_to_cpu(sh4a_get_unaligned_cpu64(p));
  91}
  92
  93static inline void nonnative_put_le16(u16 val, u8 *p)
  94{
  95        *p++ = val;
  96        *p++ = val >> 8;
  97}
  98
  99static inline void nonnative_put_le32(u32 val, u8 *p)
 100{
 101        nonnative_put_le16(val, p);
 102        nonnative_put_le16(val >> 16, p + 2);
 103}
 104
 105static inline void nonnative_put_le64(u64 val, u8 *p)
 106{
 107        nonnative_put_le32(val, p);
 108        nonnative_put_le32(val >> 32, p + 4);
 109}
 110
 111static inline void nonnative_put_be16(u16 val, u8 *p)
 112{
 113        *p++ = val >> 8;
 114        *p++ = val;
 115}
 116
 117static inline void nonnative_put_be32(u32 val, u8 *p)
 118{
 119        nonnative_put_be16(val >> 16, p);
 120        nonnative_put_be16(val, p + 2);
 121}
 122
 123static inline void nonnative_put_be64(u64 val, u8 *p)
 124{
 125        nonnative_put_be32(val >> 32, p);
 126        nonnative_put_be32(val, p + 4);
 127}
 128
 129static inline void put_unaligned_le16(u16 val, void *p)
 130{
 131#ifdef __LITTLE_ENDIAN
 132        __put_unaligned_cpu16(val, p);
 133#else
 134        nonnative_put_le16(val, p);
 135#endif
 136}
 137
 138static inline void put_unaligned_le32(u32 val, void *p)
 139{
 140#ifdef __LITTLE_ENDIAN
 141        __put_unaligned_cpu32(val, p);
 142#else
 143        nonnative_put_le32(val, p);
 144#endif
 145}
 146
 147static inline void put_unaligned_le64(u64 val, void *p)
 148{
 149#ifdef __LITTLE_ENDIAN
 150        __put_unaligned_cpu64(val, p);
 151#else
 152        nonnative_put_le64(val, p);
 153#endif
 154}
 155
 156static inline void put_unaligned_be16(u16 val, void *p)
 157{
 158#ifdef __BIG_ENDIAN
 159        __put_unaligned_cpu16(val, p);
 160#else
 161        nonnative_put_be16(val, p);
 162#endif
 163}
 164
 165static inline void put_unaligned_be32(u32 val, void *p)
 166{
 167#ifdef __BIG_ENDIAN
 168        __put_unaligned_cpu32(val, p);
 169#else
 170        nonnative_put_be32(val, p);
 171#endif
 172}
 173
 174static inline void put_unaligned_be64(u64 val, void *p)
 175{
 176#ifdef __BIG_ENDIAN
 177        __put_unaligned_cpu64(val, p);
 178#else
 179        nonnative_put_be64(val, p);
 180#endif
 181}
 182
 183/*
 184 * While it's a bit non-obvious, even though the generic le/be wrappers
 185 * use the __get/put_xxx prefixing, they actually wrap in to the
 186 * non-prefixed get/put_xxx variants as provided above.
 187 */
 188#include <linux/unaligned/generic.h>
 189
 190#ifdef __LITTLE_ENDIAN
 191# define get_unaligned __get_unaligned_le
 192# define put_unaligned __put_unaligned_le
 193#else
 194# define get_unaligned __get_unaligned_be
 195# define put_unaligned __put_unaligned_be
 196#endif
 197
 198#endif /* __ASM_SH_UNALIGNED_SH4A_H */
 199