17938f421SLucas De Marchi /* SPDX-License-Identifier: GPL-2.0-only */
27938f421SLucas De Marchi /*
37938f421SLucas De Marchi * Pointer abstraction for IO/system memory
47938f421SLucas De Marchi */
57938f421SLucas De Marchi
67938f421SLucas De Marchi #ifndef __IOSYS_MAP_H__
77938f421SLucas De Marchi #define __IOSYS_MAP_H__
87938f421SLucas De Marchi
95f278dbdSLucas De Marchi #include <linux/compiler_types.h>
107938f421SLucas De Marchi #include <linux/io.h>
117938f421SLucas De Marchi #include <linux/string.h>
127938f421SLucas De Marchi
137938f421SLucas De Marchi /**
147938f421SLucas De Marchi * DOC: overview
157938f421SLucas De Marchi *
167938f421SLucas De Marchi * When accessing a memory region, depending on its location, users may have to
177938f421SLucas De Marchi * access it with I/O operations or memory load/store operations. For example,
187938f421SLucas De Marchi * copying to system memory could be done with memcpy(), copying to I/O memory
197938f421SLucas De Marchi * would be done with memcpy_toio().
207938f421SLucas De Marchi *
217938f421SLucas De Marchi * .. code-block:: c
227938f421SLucas De Marchi *
237938f421SLucas De Marchi * void *vaddr = ...; // pointer to system memory
247938f421SLucas De Marchi * memcpy(vaddr, src, len);
257938f421SLucas De Marchi *
267938f421SLucas De Marchi * void *vaddr_iomem = ...; // pointer to I/O memory
27e4a8864fSLucas De Marchi * memcpy_toio(vaddr_iomem, src, len);
287938f421SLucas De Marchi *
297938f421SLucas De Marchi * The user of such pointer may not have information about the mapping of that
307938f421SLucas De Marchi * region or may want to have a single code path to handle operations on that
317938f421SLucas De Marchi * buffer, regardless if it's located in system or IO memory. The type
327938f421SLucas De Marchi * :c:type:`struct iosys_map <iosys_map>` and its helpers abstract that so the
337938f421SLucas De Marchi * buffer can be passed around to other drivers or have separate duties inside
347938f421SLucas De Marchi * the same driver for allocation, read and write operations.
357938f421SLucas De Marchi *
367938f421SLucas De Marchi * Open-coding access to :c:type:`struct iosys_map <iosys_map>` is considered
37*4276d28eSRandy Dunlap * bad style. Rather than accessing its fields directly, use one of the provided
387938f421SLucas De Marchi * helper functions, or implement your own. For example, instances of
397938f421SLucas De Marchi * :c:type:`struct iosys_map <iosys_map>` can be initialized statically with
407938f421SLucas De Marchi * IOSYS_MAP_INIT_VADDR(), or at runtime with iosys_map_set_vaddr(). These
417938f421SLucas De Marchi * helpers will set an address in system memory.
427938f421SLucas De Marchi *
437938f421SLucas De Marchi * .. code-block:: c
447938f421SLucas De Marchi *
457938f421SLucas De Marchi * struct iosys_map map = IOSYS_MAP_INIT_VADDR(0xdeadbeaf);
467938f421SLucas De Marchi *
477938f421SLucas De Marchi * iosys_map_set_vaddr(&map, 0xdeadbeaf);
487938f421SLucas De Marchi *
49116d902fSThomas Zimmermann * To set an address in I/O memory, use IOSYS_MAP_INIT_VADDR_IOMEM() or
50116d902fSThomas Zimmermann * iosys_map_set_vaddr_iomem().
517938f421SLucas De Marchi *
527938f421SLucas De Marchi * .. code-block:: c
537938f421SLucas De Marchi *
54116d902fSThomas Zimmermann * struct iosys_map map = IOSYS_MAP_INIT_VADDR_IOMEM(0xdeadbeaf);
55116d902fSThomas Zimmermann *
567938f421SLucas De Marchi * iosys_map_set_vaddr_iomem(&map, 0xdeadbeaf);
577938f421SLucas De Marchi *
587938f421SLucas De Marchi * Instances of struct iosys_map do not have to be cleaned up, but
597938f421SLucas De Marchi * can be cleared to NULL with iosys_map_clear(). Cleared mappings
607938f421SLucas De Marchi * always refer to system memory.
617938f421SLucas De Marchi *
627938f421SLucas De Marchi * .. code-block:: c
637938f421SLucas De Marchi *
647938f421SLucas De Marchi * iosys_map_clear(&map);
657938f421SLucas De Marchi *
667938f421SLucas De Marchi * Test if a mapping is valid with either iosys_map_is_set() or
677938f421SLucas De Marchi * iosys_map_is_null().
687938f421SLucas De Marchi *
697938f421SLucas De Marchi * .. code-block:: c
707938f421SLucas De Marchi *
717938f421SLucas De Marchi * if (iosys_map_is_set(&map) != iosys_map_is_null(&map))
727938f421SLucas De Marchi * // always true
737938f421SLucas De Marchi *
747938f421SLucas De Marchi * Instances of :c:type:`struct iosys_map <iosys_map>` can be compared for
757938f421SLucas De Marchi * equality with iosys_map_is_equal(). Mappings that point to different memory
767938f421SLucas De Marchi * spaces, system or I/O, are never equal. That's even true if both spaces are
777938f421SLucas De Marchi * located in the same address space, both mappings contain the same address
787938f421SLucas De Marchi * value, or both mappings refer to NULL.
797938f421SLucas De Marchi *
807938f421SLucas De Marchi * .. code-block:: c
817938f421SLucas De Marchi *
827938f421SLucas De Marchi * struct iosys_map sys_map; // refers to system memory
837938f421SLucas De Marchi * struct iosys_map io_map; // refers to I/O memory
847938f421SLucas De Marchi *
857938f421SLucas De Marchi * if (iosys_map_is_equal(&sys_map, &io_map))
867938f421SLucas De Marchi * // always false
877938f421SLucas De Marchi *
887938f421SLucas De Marchi * A set up instance of struct iosys_map can be used to access or manipulate the
897938f421SLucas De Marchi * buffer memory. Depending on the location of the memory, the provided helpers
907938f421SLucas De Marchi * will pick the correct operations. Data can be copied into the memory with
917938f421SLucas De Marchi * iosys_map_memcpy_to(). The address can be manipulated with iosys_map_incr().
927938f421SLucas De Marchi *
937938f421SLucas De Marchi * .. code-block:: c
947938f421SLucas De Marchi *
957938f421SLucas De Marchi * const void *src = ...; // source buffer
967938f421SLucas De Marchi * size_t len = ...; // length of src
977938f421SLucas De Marchi *
987938f421SLucas De Marchi * iosys_map_memcpy_to(&map, src, len);
997938f421SLucas De Marchi * iosys_map_incr(&map, len); // go to first byte after the memcpy
1007938f421SLucas De Marchi */
1017938f421SLucas De Marchi
1027938f421SLucas De Marchi /**
1037938f421SLucas De Marchi * struct iosys_map - Pointer to IO/system memory
1047938f421SLucas De Marchi * @vaddr_iomem: The buffer's address if in I/O memory
1057938f421SLucas De Marchi * @vaddr: The buffer's address if in system memory
1067938f421SLucas De Marchi * @is_iomem: True if the buffer is located in I/O memory, or false
1077938f421SLucas De Marchi * otherwise.
1087938f421SLucas De Marchi */
1097938f421SLucas De Marchi struct iosys_map {
1107938f421SLucas De Marchi union {
1117938f421SLucas De Marchi void __iomem *vaddr_iomem;
1127938f421SLucas De Marchi void *vaddr;
1137938f421SLucas De Marchi };
1147938f421SLucas De Marchi bool is_iomem;
1157938f421SLucas De Marchi };
1167938f421SLucas De Marchi
1177938f421SLucas De Marchi /**
1187938f421SLucas De Marchi * IOSYS_MAP_INIT_VADDR - Initializes struct iosys_map to an address in system memory
1197938f421SLucas De Marchi * @vaddr_: A system-memory address
1207938f421SLucas De Marchi */
1217938f421SLucas De Marchi #define IOSYS_MAP_INIT_VADDR(vaddr_) \
1227938f421SLucas De Marchi { \
1237938f421SLucas De Marchi .vaddr = (vaddr_), \
1247938f421SLucas De Marchi .is_iomem = false, \
1257938f421SLucas De Marchi }
1267938f421SLucas De Marchi
1277938f421SLucas De Marchi /**
128116d902fSThomas Zimmermann * IOSYS_MAP_INIT_VADDR_IOMEM - Initializes struct iosys_map to an address in I/O memory
129116d902fSThomas Zimmermann * @vaddr_iomem_: An I/O-memory address
130116d902fSThomas Zimmermann */
131116d902fSThomas Zimmermann #define IOSYS_MAP_INIT_VADDR_IOMEM(vaddr_iomem_) \
132116d902fSThomas Zimmermann { \
133116d902fSThomas Zimmermann .vaddr_iomem = (vaddr_iomem_), \
134116d902fSThomas Zimmermann .is_iomem = true, \
135116d902fSThomas Zimmermann }
136116d902fSThomas Zimmermann
137116d902fSThomas Zimmermann /**
138e62f25e8SLucas De Marchi * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
139e62f25e8SLucas De Marchi * @map_: The dma-buf mapping structure to copy from
140e62f25e8SLucas De Marchi * @offset_: Offset to add to the other mapping
141e62f25e8SLucas De Marchi *
142e62f25e8SLucas De Marchi * Initializes a new iosys_map struct based on another passed as argument. It
143e62f25e8SLucas De Marchi * does a shallow copy of the struct so it's possible to update the back storage
144e62f25e8SLucas De Marchi * without changing where the original map points to. It is the equivalent of
145e62f25e8SLucas De Marchi * doing:
146e62f25e8SLucas De Marchi *
147e62f25e8SLucas De Marchi * .. code-block:: c
148e62f25e8SLucas De Marchi *
149e62f25e8SLucas De Marchi * iosys_map map = other_map;
150e62f25e8SLucas De Marchi * iosys_map_incr(&map, &offset);
151e62f25e8SLucas De Marchi *
152e62f25e8SLucas De Marchi * Example usage:
153e62f25e8SLucas De Marchi *
154e62f25e8SLucas De Marchi * .. code-block:: c
155e62f25e8SLucas De Marchi *
156e62f25e8SLucas De Marchi * void foo(struct device *dev, struct iosys_map *base_map)
157e62f25e8SLucas De Marchi * {
158e62f25e8SLucas De Marchi * ...
159e62f25e8SLucas De Marchi * struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, FIELD_OFFSET);
160e62f25e8SLucas De Marchi * ...
161e62f25e8SLucas De Marchi * }
162e62f25e8SLucas De Marchi *
163e62f25e8SLucas De Marchi * The advantage of using the initializer over just increasing the offset with
164e62f25e8SLucas De Marchi * iosys_map_incr() like above is that the new map will always point to the
165e62f25e8SLucas De Marchi * right place of the buffer during its scope. It reduces the risk of updating
166e62f25e8SLucas De Marchi * the wrong part of the buffer and having no compiler warning about that. If
167e62f25e8SLucas De Marchi * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can warn
168e62f25e8SLucas De Marchi * about the use of uninitialized variable.
169e62f25e8SLucas De Marchi */
170e62f25e8SLucas De Marchi #define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({ \
1712e122362SMichał Winiarski struct iosys_map copy_ = *map_; \
1722e122362SMichał Winiarski iosys_map_incr(©_, offset_); \
1732e122362SMichał Winiarski copy_; \
174e62f25e8SLucas De Marchi })
175e62f25e8SLucas De Marchi
176e62f25e8SLucas De Marchi /**
1777938f421SLucas De Marchi * iosys_map_set_vaddr - Sets a iosys mapping structure to an address in system memory
1787938f421SLucas De Marchi * @map: The iosys_map structure
1797938f421SLucas De Marchi * @vaddr: A system-memory address
1807938f421SLucas De Marchi *
1817938f421SLucas De Marchi * Sets the address and clears the I/O-memory flag.
1827938f421SLucas De Marchi */
iosys_map_set_vaddr(struct iosys_map * map,void * vaddr)1837938f421SLucas De Marchi static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr)
1847938f421SLucas De Marchi {
1857938f421SLucas De Marchi map->vaddr = vaddr;
1867938f421SLucas De Marchi map->is_iomem = false;
1877938f421SLucas De Marchi }
1887938f421SLucas De Marchi
1897938f421SLucas De Marchi /**
1907938f421SLucas De Marchi * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address in I/O memory
1917938f421SLucas De Marchi * @map: The iosys_map structure
1927938f421SLucas De Marchi * @vaddr_iomem: An I/O-memory address
1937938f421SLucas De Marchi *
1947938f421SLucas De Marchi * Sets the address and the I/O-memory flag.
1957938f421SLucas De Marchi */
iosys_map_set_vaddr_iomem(struct iosys_map * map,void __iomem * vaddr_iomem)1967938f421SLucas De Marchi static inline void iosys_map_set_vaddr_iomem(struct iosys_map *map,
1977938f421SLucas De Marchi void __iomem *vaddr_iomem)
1987938f421SLucas De Marchi {
1997938f421SLucas De Marchi map->vaddr_iomem = vaddr_iomem;
2007938f421SLucas De Marchi map->is_iomem = true;
2017938f421SLucas De Marchi }
2027938f421SLucas De Marchi
2037938f421SLucas De Marchi /**
2047938f421SLucas De Marchi * iosys_map_is_equal - Compares two iosys mapping structures for equality
2057938f421SLucas De Marchi * @lhs: The iosys_map structure
2067938f421SLucas De Marchi * @rhs: A iosys_map structure to compare with
2077938f421SLucas De Marchi *
2087938f421SLucas De Marchi * Two iosys mapping structures are equal if they both refer to the same type of memory
2097938f421SLucas De Marchi * and to the same address within that memory.
2107938f421SLucas De Marchi *
2117938f421SLucas De Marchi * Returns:
2127938f421SLucas De Marchi * True is both structures are equal, or false otherwise.
2137938f421SLucas De Marchi */
iosys_map_is_equal(const struct iosys_map * lhs,const struct iosys_map * rhs)2147938f421SLucas De Marchi static inline bool iosys_map_is_equal(const struct iosys_map *lhs,
2157938f421SLucas De Marchi const struct iosys_map *rhs)
2167938f421SLucas De Marchi {
2177938f421SLucas De Marchi if (lhs->is_iomem != rhs->is_iomem)
2187938f421SLucas De Marchi return false;
2197938f421SLucas De Marchi else if (lhs->is_iomem)
2207938f421SLucas De Marchi return lhs->vaddr_iomem == rhs->vaddr_iomem;
2217938f421SLucas De Marchi else
2227938f421SLucas De Marchi return lhs->vaddr == rhs->vaddr;
2237938f421SLucas De Marchi }
2247938f421SLucas De Marchi
2257938f421SLucas De Marchi /**
2267938f421SLucas De Marchi * iosys_map_is_null - Tests for a iosys mapping to be NULL
2277938f421SLucas De Marchi * @map: The iosys_map structure
2287938f421SLucas De Marchi *
2297938f421SLucas De Marchi * Depending on the state of struct iosys_map.is_iomem, tests if the
2307938f421SLucas De Marchi * mapping is NULL.
2317938f421SLucas De Marchi *
2327938f421SLucas De Marchi * Returns:
2337938f421SLucas De Marchi * True if the mapping is NULL, or false otherwise.
2347938f421SLucas De Marchi */
iosys_map_is_null(const struct iosys_map * map)2357938f421SLucas De Marchi static inline bool iosys_map_is_null(const struct iosys_map *map)
2367938f421SLucas De Marchi {
2377938f421SLucas De Marchi if (map->is_iomem)
2387938f421SLucas De Marchi return !map->vaddr_iomem;
2397938f421SLucas De Marchi return !map->vaddr;
2407938f421SLucas De Marchi }
2417938f421SLucas De Marchi
2427938f421SLucas De Marchi /**
2437938f421SLucas De Marchi * iosys_map_is_set - Tests if the iosys mapping has been set
2447938f421SLucas De Marchi * @map: The iosys_map structure
2457938f421SLucas De Marchi *
2467938f421SLucas De Marchi * Depending on the state of struct iosys_map.is_iomem, tests if the
2477938f421SLucas De Marchi * mapping has been set.
2487938f421SLucas De Marchi *
2497938f421SLucas De Marchi * Returns:
2507938f421SLucas De Marchi * True if the mapping is been set, or false otherwise.
2517938f421SLucas De Marchi */
iosys_map_is_set(const struct iosys_map * map)2527938f421SLucas De Marchi static inline bool iosys_map_is_set(const struct iosys_map *map)
2537938f421SLucas De Marchi {
2547938f421SLucas De Marchi return !iosys_map_is_null(map);
2557938f421SLucas De Marchi }
2567938f421SLucas De Marchi
2577938f421SLucas De Marchi /**
2587938f421SLucas De Marchi * iosys_map_clear - Clears a iosys mapping structure
2597938f421SLucas De Marchi * @map: The iosys_map structure
2607938f421SLucas De Marchi *
2617938f421SLucas De Marchi * Clears all fields to zero, including struct iosys_map.is_iomem, so
2627938f421SLucas De Marchi * mapping structures that were set to point to I/O memory are reset for
2637938f421SLucas De Marchi * system memory. Pointers are cleared to NULL. This is the default.
2647938f421SLucas De Marchi */
iosys_map_clear(struct iosys_map * map)2657938f421SLucas De Marchi static inline void iosys_map_clear(struct iosys_map *map)
2667938f421SLucas De Marchi {
2677938f421SLucas De Marchi if (map->is_iomem) {
2687938f421SLucas De Marchi map->vaddr_iomem = NULL;
2697938f421SLucas De Marchi map->is_iomem = false;
2707938f421SLucas De Marchi } else {
2717938f421SLucas De Marchi map->vaddr = NULL;
2727938f421SLucas De Marchi }
2737938f421SLucas De Marchi }
2747938f421SLucas De Marchi
2757938f421SLucas De Marchi /**
276cccd73d6SLucas De Marchi * iosys_map_memcpy_to - Memcpy into offset of iosys_map
2777938f421SLucas De Marchi * @dst: The iosys_map structure
278cccd73d6SLucas De Marchi * @dst_offset: The offset from which to copy
2797938f421SLucas De Marchi * @src: The source buffer
2807938f421SLucas De Marchi * @len: The number of byte in src
2817938f421SLucas De Marchi *
282cccd73d6SLucas De Marchi * Copies data into a iosys_map with an offset. The source buffer is in
283cccd73d6SLucas De Marchi * system memory. Depending on the buffer's location, the helper picks the
284cccd73d6SLucas De Marchi * correct method of accessing the memory.
2857938f421SLucas De Marchi */
iosys_map_memcpy_to(struct iosys_map * dst,size_t dst_offset,const void * src,size_t len)286cccd73d6SLucas De Marchi static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset,
287cccd73d6SLucas De Marchi const void *src, size_t len)
2887938f421SLucas De Marchi {
2897938f421SLucas De Marchi if (dst->is_iomem)
290cccd73d6SLucas De Marchi memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
2917938f421SLucas De Marchi else
292cccd73d6SLucas De Marchi memcpy(dst->vaddr + dst_offset, src, len);
2937938f421SLucas De Marchi }
2947938f421SLucas De Marchi
2957938f421SLucas De Marchi /**
296e62f25e8SLucas De Marchi * iosys_map_memcpy_from - Memcpy from iosys_map into system memory
297e62f25e8SLucas De Marchi * @dst: Destination in system memory
298e62f25e8SLucas De Marchi * @src: The iosys_map structure
299e62f25e8SLucas De Marchi * @src_offset: The offset from which to copy
300e62f25e8SLucas De Marchi * @len: The number of byte in src
301e62f25e8SLucas De Marchi *
302e62f25e8SLucas De Marchi * Copies data from a iosys_map with an offset. The dest buffer is in
303e62f25e8SLucas De Marchi * system memory. Depending on the mapping location, the helper picks the
304e62f25e8SLucas De Marchi * correct method of accessing the memory.
305e62f25e8SLucas De Marchi */
iosys_map_memcpy_from(void * dst,const struct iosys_map * src,size_t src_offset,size_t len)306e62f25e8SLucas De Marchi static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map *src,
307e62f25e8SLucas De Marchi size_t src_offset, size_t len)
308e62f25e8SLucas De Marchi {
309e62f25e8SLucas De Marchi if (src->is_iomem)
310e62f25e8SLucas De Marchi memcpy_fromio(dst, src->vaddr_iomem + src_offset, len);
311e62f25e8SLucas De Marchi else
312e62f25e8SLucas De Marchi memcpy(dst, src->vaddr + src_offset, len);
313e62f25e8SLucas De Marchi }
314e62f25e8SLucas De Marchi
315e62f25e8SLucas De Marchi /**
3167938f421SLucas De Marchi * iosys_map_incr - Increments the address stored in a iosys mapping
3177938f421SLucas De Marchi * @map: The iosys_map structure
3187938f421SLucas De Marchi * @incr: The number of bytes to increment
3197938f421SLucas De Marchi *
3207938f421SLucas De Marchi * Increments the address stored in a iosys mapping. Depending on the
3217938f421SLucas De Marchi * buffer's location, the correct value will be updated.
3227938f421SLucas De Marchi */
iosys_map_incr(struct iosys_map * map,size_t incr)3237938f421SLucas De Marchi static inline void iosys_map_incr(struct iosys_map *map, size_t incr)
3247938f421SLucas De Marchi {
3257938f421SLucas De Marchi if (map->is_iomem)
3267938f421SLucas De Marchi map->vaddr_iomem += incr;
3277938f421SLucas De Marchi else
3287938f421SLucas De Marchi map->vaddr += incr;
3297938f421SLucas De Marchi }
3307938f421SLucas De Marchi
331e62f25e8SLucas De Marchi /**
332e62f25e8SLucas De Marchi * iosys_map_memset - Memset iosys_map
333e62f25e8SLucas De Marchi * @dst: The iosys_map structure
334e62f25e8SLucas De Marchi * @offset: Offset from dst where to start setting value
335e62f25e8SLucas De Marchi * @value: The value to set
336e62f25e8SLucas De Marchi * @len: The number of bytes to set in dst
337e62f25e8SLucas De Marchi *
338e62f25e8SLucas De Marchi * Set value in iosys_map. Depending on the buffer's location, the helper
339e62f25e8SLucas De Marchi * picks the correct method of accessing the memory.
340e62f25e8SLucas De Marchi */
iosys_map_memset(struct iosys_map * dst,size_t offset,int value,size_t len)341e62f25e8SLucas De Marchi static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
342e62f25e8SLucas De Marchi int value, size_t len)
343e62f25e8SLucas De Marchi {
344e62f25e8SLucas De Marchi if (dst->is_iomem)
345e62f25e8SLucas De Marchi memset_io(dst->vaddr_iomem + offset, value, len);
346e62f25e8SLucas De Marchi else
347e62f25e8SLucas De Marchi memset(dst->vaddr + offset, value, len);
348e62f25e8SLucas De Marchi }
349e62f25e8SLucas De Marchi
3505f278dbdSLucas De Marchi #ifdef CONFIG_64BIT
3515f278dbdSLucas De Marchi #define __iosys_map_rd_io_u64_case(val_, vaddr_iomem_) \
3525f278dbdSLucas De Marchi u64: val_ = readq(vaddr_iomem_)
3536fb5ee7cSLucas De Marchi #define __iosys_map_wr_io_u64_case(val_, vaddr_iomem_) \
3546fb5ee7cSLucas De Marchi u64: writeq(val_, vaddr_iomem_)
3555f278dbdSLucas De Marchi #else
3565f278dbdSLucas De Marchi #define __iosys_map_rd_io_u64_case(val_, vaddr_iomem_) \
3575f278dbdSLucas De Marchi u64: memcpy_fromio(&(val_), vaddr_iomem_, sizeof(u64))
3586fb5ee7cSLucas De Marchi #define __iosys_map_wr_io_u64_case(val_, vaddr_iomem_) \
3596fb5ee7cSLucas De Marchi u64: memcpy_toio(vaddr_iomem_, &(val_), sizeof(u64))
3605f278dbdSLucas De Marchi #endif
3615f278dbdSLucas De Marchi
3625f278dbdSLucas De Marchi #define __iosys_map_rd_io(val__, vaddr_iomem__, type__) _Generic(val__, \
3635f278dbdSLucas De Marchi u8: val__ = readb(vaddr_iomem__), \
3645f278dbdSLucas De Marchi u16: val__ = readw(vaddr_iomem__), \
3655f278dbdSLucas De Marchi u32: val__ = readl(vaddr_iomem__), \
3665f278dbdSLucas De Marchi __iosys_map_rd_io_u64_case(val__, vaddr_iomem__))
3675f278dbdSLucas De Marchi
3685f278dbdSLucas De Marchi #define __iosys_map_rd_sys(val__, vaddr__, type__) \
3695f278dbdSLucas De Marchi val__ = READ_ONCE(*(type__ *)(vaddr__))
3705f278dbdSLucas De Marchi
3716fb5ee7cSLucas De Marchi #define __iosys_map_wr_io(val__, vaddr_iomem__, type__) _Generic(val__, \
3726fb5ee7cSLucas De Marchi u8: writeb(val__, vaddr_iomem__), \
3736fb5ee7cSLucas De Marchi u16: writew(val__, vaddr_iomem__), \
3746fb5ee7cSLucas De Marchi u32: writel(val__, vaddr_iomem__), \
3756fb5ee7cSLucas De Marchi __iosys_map_wr_io_u64_case(val__, vaddr_iomem__))
3766fb5ee7cSLucas De Marchi
3776fb5ee7cSLucas De Marchi #define __iosys_map_wr_sys(val__, vaddr__, type__) \
3786fb5ee7cSLucas De Marchi WRITE_ONCE(*(type__ *)(vaddr__), val__)
3796fb5ee7cSLucas De Marchi
380e62f25e8SLucas De Marchi /**
381e62f25e8SLucas De Marchi * iosys_map_rd - Read a C-type value from the iosys_map
382e62f25e8SLucas De Marchi *
383e62f25e8SLucas De Marchi * @map__: The iosys_map structure
384e62f25e8SLucas De Marchi * @offset__: The offset from which to read
385e62f25e8SLucas De Marchi * @type__: Type of the value being read
386e62f25e8SLucas De Marchi *
3875f278dbdSLucas De Marchi * Read a C type value (u8, u16, u32 and u64) from iosys_map. For other types or
3885f278dbdSLucas De Marchi * if pointer may be unaligned (and problematic for the architecture supported),
3895f278dbdSLucas De Marchi * use iosys_map_memcpy_from().
390e62f25e8SLucas De Marchi *
391e62f25e8SLucas De Marchi * Returns:
392e62f25e8SLucas De Marchi * The value read from the mapping.
393e62f25e8SLucas De Marchi */
394e62f25e8SLucas De Marchi #define iosys_map_rd(map__, offset__, type__) ({ \
3952e122362SMichał Winiarski type__ val_; \
3965f278dbdSLucas De Marchi if ((map__)->is_iomem) { \
3972e122362SMichał Winiarski __iosys_map_rd_io(val_, (map__)->vaddr_iomem + (offset__), type__); \
3985f278dbdSLucas De Marchi } else { \
3992e122362SMichał Winiarski __iosys_map_rd_sys(val_, (map__)->vaddr + (offset__), type__); \
4005f278dbdSLucas De Marchi } \
4012e122362SMichał Winiarski val_; \
402e62f25e8SLucas De Marchi })
403e62f25e8SLucas De Marchi
404e62f25e8SLucas De Marchi /**
405e62f25e8SLucas De Marchi * iosys_map_wr - Write a C-type value to the iosys_map
406e62f25e8SLucas De Marchi *
407e62f25e8SLucas De Marchi * @map__: The iosys_map structure
408e62f25e8SLucas De Marchi * @offset__: The offset from the mapping to write to
409e62f25e8SLucas De Marchi * @type__: Type of the value being written
410e62f25e8SLucas De Marchi * @val__: Value to write
411e62f25e8SLucas De Marchi *
4126fb5ee7cSLucas De Marchi * Write a C type value (u8, u16, u32 and u64) to the iosys_map. For other types
4136fb5ee7cSLucas De Marchi * or if pointer may be unaligned (and problematic for the architecture
4146fb5ee7cSLucas De Marchi * supported), use iosys_map_memcpy_to()
415e62f25e8SLucas De Marchi */
416e62f25e8SLucas De Marchi #define iosys_map_wr(map__, offset__, type__, val__) ({ \
4172e122362SMichał Winiarski type__ val_ = (val__); \
4186fb5ee7cSLucas De Marchi if ((map__)->is_iomem) { \
4192e122362SMichał Winiarski __iosys_map_wr_io(val_, (map__)->vaddr_iomem + (offset__), type__); \
4206fb5ee7cSLucas De Marchi } else { \
4212e122362SMichał Winiarski __iosys_map_wr_sys(val_, (map__)->vaddr + (offset__), type__); \
4226fb5ee7cSLucas De Marchi } \
423e62f25e8SLucas De Marchi })
424e62f25e8SLucas De Marchi
425e62f25e8SLucas De Marchi /**
426e62f25e8SLucas De Marchi * iosys_map_rd_field - Read a member from a struct in the iosys_map
427e62f25e8SLucas De Marchi *
428e62f25e8SLucas De Marchi * @map__: The iosys_map structure
429b9f29205SRandy Dunlap * @struct_offset__: Offset from the beginning of the map, where the struct
430e62f25e8SLucas De Marchi * is located
431e62f25e8SLucas De Marchi * @struct_type__: The struct describing the layout of the mapping
432e62f25e8SLucas De Marchi * @field__: Member of the struct to read
433e62f25e8SLucas De Marchi *
434e62f25e8SLucas De Marchi * Read a value from iosys_map considering its layout is described by a C struct
435e62f25e8SLucas De Marchi * starting at @struct_offset__. The field offset and size is calculated and its
4365f278dbdSLucas De Marchi * value read. If the field access would incur in un-aligned access, then either
4375f278dbdSLucas De Marchi * iosys_map_memcpy_from() needs to be used or the architecture must support it.
4385f278dbdSLucas De Marchi * For example: suppose there is a @struct foo defined as below and the value
4395f278dbdSLucas De Marchi * ``foo.field2.inner2`` needs to be read from the iosys_map:
440e62f25e8SLucas De Marchi *
441e62f25e8SLucas De Marchi * .. code-block:: c
442e62f25e8SLucas De Marchi *
443e62f25e8SLucas De Marchi * struct foo {
444e62f25e8SLucas De Marchi * int field1;
445e62f25e8SLucas De Marchi * struct {
446e62f25e8SLucas De Marchi * int inner1;
447e62f25e8SLucas De Marchi * int inner2;
448e62f25e8SLucas De Marchi * } field2;
449e62f25e8SLucas De Marchi * int field3;
450e62f25e8SLucas De Marchi * } __packed;
451e62f25e8SLucas De Marchi *
452e62f25e8SLucas De Marchi * This is the expected memory layout of a buffer using iosys_map_rd_field():
453e62f25e8SLucas De Marchi *
454e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
455e62f25e8SLucas De Marchi * | Address | Content |
456e62f25e8SLucas De Marchi * +==============================+==========================+
457e62f25e8SLucas De Marchi * | buffer + 0000 | start of mmapped buffer |
458e62f25e8SLucas De Marchi * | | pointed by iosys_map |
459e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
460e62f25e8SLucas De Marchi * | ... | ... |
461e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
462e62f25e8SLucas De Marchi * | buffer + ``struct_offset__`` | start of ``struct foo`` |
463e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
464e62f25e8SLucas De Marchi * | ... | ... |
465e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
466e62f25e8SLucas De Marchi * | buffer + wwww | ``foo.field2.inner2`` |
467e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
468e62f25e8SLucas De Marchi * | ... | ... |
469e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
470e62f25e8SLucas De Marchi * | buffer + yyyy | end of ``struct foo`` |
471e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
472e62f25e8SLucas De Marchi * | ... | ... |
473e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
474e62f25e8SLucas De Marchi * | buffer + zzzz | end of mmaped buffer |
475e62f25e8SLucas De Marchi * +------------------------------+--------------------------+
476e62f25e8SLucas De Marchi *
477e62f25e8SLucas De Marchi * Values automatically calculated by this macro or not needed are denoted by
478e62f25e8SLucas De Marchi * wwww, yyyy and zzzz. This is the code to read that value:
479e62f25e8SLucas De Marchi *
480e62f25e8SLucas De Marchi * .. code-block:: c
481e62f25e8SLucas De Marchi *
482e62f25e8SLucas De Marchi * x = iosys_map_rd_field(&map, offset, struct foo, field2.inner2);
483e62f25e8SLucas De Marchi *
484e62f25e8SLucas De Marchi * Returns:
485e62f25e8SLucas De Marchi * The value read from the mapping.
486e62f25e8SLucas De Marchi */
487e62f25e8SLucas De Marchi #define iosys_map_rd_field(map__, struct_offset__, struct_type__, field__) ({ \
4882e122362SMichał Winiarski struct_type__ *s_; \
489e62f25e8SLucas De Marchi iosys_map_rd(map__, struct_offset__ + offsetof(struct_type__, field__), \
4902e122362SMichał Winiarski typeof(s_->field__)); \
491e62f25e8SLucas De Marchi })
492e62f25e8SLucas De Marchi
493e62f25e8SLucas De Marchi /**
494e62f25e8SLucas De Marchi * iosys_map_wr_field - Write to a member of a struct in the iosys_map
495e62f25e8SLucas De Marchi *
496e62f25e8SLucas De Marchi * @map__: The iosys_map structure
497b9f29205SRandy Dunlap * @struct_offset__: Offset from the beginning of the map, where the struct
498e62f25e8SLucas De Marchi * is located
499e62f25e8SLucas De Marchi * @struct_type__: The struct describing the layout of the mapping
500e62f25e8SLucas De Marchi * @field__: Member of the struct to read
501e62f25e8SLucas De Marchi * @val__: Value to write
502e62f25e8SLucas De Marchi *
5036fb5ee7cSLucas De Marchi * Write a value to the iosys_map considering its layout is described by a C
5046fb5ee7cSLucas De Marchi * struct starting at @struct_offset__. The field offset and size is calculated
5056fb5ee7cSLucas De Marchi * and the @val__ is written. If the field access would incur in un-aligned
5066fb5ee7cSLucas De Marchi * access, then either iosys_map_memcpy_to() needs to be used or the
5076fb5ee7cSLucas De Marchi * architecture must support it. Refer to iosys_map_rd_field() for expected
5086fb5ee7cSLucas De Marchi * usage and memory layout.
509e62f25e8SLucas De Marchi */
510e62f25e8SLucas De Marchi #define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({ \
5112e122362SMichał Winiarski struct_type__ *s_; \
512e62f25e8SLucas De Marchi iosys_map_wr(map__, struct_offset__ + offsetof(struct_type__, field__), \
5132e122362SMichał Winiarski typeof(s_->field__), val__); \
514e62f25e8SLucas De Marchi })
515e62f25e8SLucas De Marchi
5167938f421SLucas De Marchi #endif /* __IOSYS_MAP_H__ */
517