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