Skip to content

Commit

Permalink
iosys-map: Add per-word write
Browse files Browse the repository at this point in the history
Like was done for read, provide the equivalent for write. Even if
current users are not in the hot path, this should future-proof it.

v2:
  - Remove default from _Generic() - callers wanting to write more
    than u64 should use iosys_map_memcpy_to()
  - Add WRITE_ONCE() cases dereferencing the pointer when using system
    memory
v3:
  - Fix precedence issue when casting inside WRITE_ONCE(). By not using ()
    around vaddr__ the offset was not part of the cast, but rather added
    to it, producing a wrong address
  - Remove compiletime_assert() as WRITE_ONCE() already contains it

Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
Reviewed-by: Reviewed-by: Christian König <christian.koenig@amd.com> # v1
Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de>
Link: https://patchwork.freedesktop.org/patch/msgid/20220628191016.3899428-2-lucas.demarchi@intel.com
  • Loading branch information
Lucas De Marchi committed Jun 30, 2022
1 parent 5f278db commit 6fb5ee7
Showing 1 changed file with 29 additions and 9 deletions.
38 changes: 29 additions & 9 deletions include/linux/iosys-map.h
Original file line number Diff line number Diff line change
Expand Up @@ -337,9 +337,13 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
#ifdef CONFIG_64BIT
#define __iosys_map_rd_io_u64_case(val_, vaddr_iomem_) \
u64: val_ = readq(vaddr_iomem_)
#define __iosys_map_wr_io_u64_case(val_, vaddr_iomem_) \
u64: writeq(val_, vaddr_iomem_)
#else
#define __iosys_map_rd_io_u64_case(val_, vaddr_iomem_) \
u64: memcpy_fromio(&(val_), vaddr_iomem_, sizeof(u64))
#define __iosys_map_wr_io_u64_case(val_, vaddr_iomem_) \
u64: memcpy_toio(vaddr_iomem_, &(val_), sizeof(u64))
#endif

#define __iosys_map_rd_io(val__, vaddr_iomem__, type__) _Generic(val__, \
Expand All @@ -351,6 +355,15 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
#define __iosys_map_rd_sys(val__, vaddr__, type__) \
val__ = READ_ONCE(*(type__ *)(vaddr__))

#define __iosys_map_wr_io(val__, vaddr_iomem__, type__) _Generic(val__, \
u8: writeb(val__, vaddr_iomem__), \
u16: writew(val__, vaddr_iomem__), \
u32: writel(val__, vaddr_iomem__), \
__iosys_map_wr_io_u64_case(val__, vaddr_iomem__))

#define __iosys_map_wr_sys(val__, vaddr__, type__) \
WRITE_ONCE(*(type__ *)(vaddr__), val__)

/**
* iosys_map_rd - Read a C-type value from the iosys_map
*
Expand Down Expand Up @@ -383,12 +396,17 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
* @type__: Type of the value being written
* @val__: Value to write
*
* Write a C-type value to the iosys_map, handling possible un-aligned accesses
* to the mapping.
* Write a C type value (u8, u16, u32 and u64) to the iosys_map. For other types
* or if pointer may be unaligned (and problematic for the architecture
* supported), use iosys_map_memcpy_to()
*/
#define iosys_map_wr(map__, offset__, type__, val__) ({ \
type__ val = (val__); \
iosys_map_memcpy_to(map__, offset__, &val, sizeof(val)); \
#define iosys_map_wr(map__, offset__, type__, val__) ({ \
type__ val = (val__); \
if ((map__)->is_iomem) { \
__iosys_map_wr_io(val, (map__)->vaddr_iomem + (offset__), type__);\
} else { \
__iosys_map_wr_sys(val, (map__)->vaddr + (offset__), type__); \
} \
})

/**
Expand Down Expand Up @@ -469,10 +487,12 @@ static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
* @field__: Member of the struct to read
* @val__: Value to write
*
* Write a value to the iosys_map considering its layout is described by a C struct
* starting at @struct_offset__. The field offset and size is calculated and the
* @val__ is written handling possible un-aligned memory accesses. Refer to
* iosys_map_rd_field() for expected usage and memory layout.
* Write a value to the iosys_map considering its layout is described by a C
* struct starting at @struct_offset__. The field offset and size is calculated
* and the @val__ is written. If the field access would incur in un-aligned
* access, then either iosys_map_memcpy_to() needs to be used or the
* architecture must support it. Refer to iosys_map_rd_field() for expected
* usage and memory layout.
*/
#define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({ \
struct_type__ *s; \
Expand Down

0 comments on commit 6fb5ee7

Please sign in to comment.