xref: /linux-6.15/include/linux/iosys-map.h (revision 4276d28e)
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(&copy_, 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