1 /* SPDX-License-Identifier: GPL-2.0-only */
2 /*
3  * Pointer abstraction for IO/system memory
4  */
5 
6 #ifndef __IOSYS_MAP_H__
7 #define __IOSYS_MAP_H__
8 
9 #include <linux/io.h>
10 #include <linux/string.h>
11 
12 /**
13  * DOC: overview
14  *
15  * When accessing a memory region, depending on its location, users may have to
16  * access it with I/O operations or memory load/store operations. For example,
17  * copying to system memory could be done with memcpy(), copying to I/O memory
18  * would be done with memcpy_toio().
19  *
20  * .. code-block:: c
21  *
22  *	void *vaddr = ...; // pointer to system memory
23  *	memcpy(vaddr, src, len);
24  *
25  *	void *vaddr_iomem = ...; // pointer to I/O memory
26  *	memcpy_toio(vaddr, _iomem, src, len);
27  *
28  * The user of such pointer may not have information about the mapping of that
29  * region or may want to have a single code path to handle operations on that
30  * buffer, regardless if it's located in system or IO memory. The type
31  * :c:type:`struct iosys_map <iosys_map>` and its helpers abstract that so the
32  * buffer can be passed around to other drivers or have separate duties inside
33  * the same driver for allocation, read and write operations.
34  *
35  * Open-coding access to :c:type:`struct iosys_map <iosys_map>` is considered
36  * bad style. Rather then accessing its fields directly, use one of the provided
37  * helper functions, or implement your own. For example, instances of
38  * :c:type:`struct iosys_map <iosys_map>` can be initialized statically with
39  * IOSYS_MAP_INIT_VADDR(), or at runtime with iosys_map_set_vaddr(). These
40  * helpers will set an address in system memory.
41  *
42  * .. code-block:: c
43  *
44  *	struct iosys_map map = IOSYS_MAP_INIT_VADDR(0xdeadbeaf);
45  *
46  *	iosys_map_set_vaddr(&map, 0xdeadbeaf);
47  *
48  * To set an address in I/O memory, use iosys_map_set_vaddr_iomem().
49  *
50  * .. code-block:: c
51  *
52  *	iosys_map_set_vaddr_iomem(&map, 0xdeadbeaf);
53  *
54  * Instances of struct iosys_map do not have to be cleaned up, but
55  * can be cleared to NULL with iosys_map_clear(). Cleared mappings
56  * always refer to system memory.
57  *
58  * .. code-block:: c
59  *
60  *	iosys_map_clear(&map);
61  *
62  * Test if a mapping is valid with either iosys_map_is_set() or
63  * iosys_map_is_null().
64  *
65  * .. code-block:: c
66  *
67  *	if (iosys_map_is_set(&map) != iosys_map_is_null(&map))
68  *		// always true
69  *
70  * Instances of :c:type:`struct iosys_map <iosys_map>` can be compared for
71  * equality with iosys_map_is_equal(). Mappings that point to different memory
72  * spaces, system or I/O, are never equal. That's even true if both spaces are
73  * located in the same address space, both mappings contain the same address
74  * value, or both mappings refer to NULL.
75  *
76  * .. code-block:: c
77  *
78  *	struct iosys_map sys_map; // refers to system memory
79  *	struct iosys_map io_map; // refers to I/O memory
80  *
81  *	if (iosys_map_is_equal(&sys_map, &io_map))
82  *		// always false
83  *
84  * A set up instance of struct iosys_map can be used to access or manipulate the
85  * buffer memory. Depending on the location of the memory, the provided helpers
86  * will pick the correct operations. Data can be copied into the memory with
87  * iosys_map_memcpy_to(). The address can be manipulated with iosys_map_incr().
88  *
89  * .. code-block:: c
90  *
91  *	const void *src = ...; // source buffer
92  *	size_t len = ...; // length of src
93  *
94  *	iosys_map_memcpy_to(&map, src, len);
95  *	iosys_map_incr(&map, len); // go to first byte after the memcpy
96  */
97 
98 /**
99  * struct iosys_map - Pointer to IO/system memory
100  * @vaddr_iomem:	The buffer's address if in I/O memory
101  * @vaddr:		The buffer's address if in system memory
102  * @is_iomem:		True if the buffer is located in I/O memory, or false
103  *			otherwise.
104  */
105 struct iosys_map {
106 	union {
107 		void __iomem *vaddr_iomem;
108 		void *vaddr;
109 	};
110 	bool is_iomem;
111 };
112 
113 /**
114  * IOSYS_MAP_INIT_VADDR - Initializes struct iosys_map to an address in system memory
115  * @vaddr_:	A system-memory address
116  */
117 #define IOSYS_MAP_INIT_VADDR(vaddr_)	\
118 	{				\
119 		.vaddr = (vaddr_),	\
120 		.is_iomem = false,	\
121 	}
122 
123 /**
124  * IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
125  * @map_:	The dma-buf mapping structure to copy from
126  * @offset_:	Offset to add to the other mapping
127  *
128  * Initializes a new iosys_map struct based on another passed as argument. It
129  * does a shallow copy of the struct so it's possible to update the back storage
130  * without changing where the original map points to. It is the equivalent of
131  * doing:
132  *
133  * .. code-block:: c
134  *
135  *	iosys_map map = other_map;
136  *	iosys_map_incr(&map, &offset);
137  *
138  * Example usage:
139  *
140  * .. code-block:: c
141  *
142  *	void foo(struct device *dev, struct iosys_map *base_map)
143  *	{
144  *		...
145  *		struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, FIELD_OFFSET);
146  *		...
147  *	}
148  *
149  * The advantage of using the initializer over just increasing the offset with
150  * iosys_map_incr() like above is that the new map will always point to the
151  * right place of the buffer during its scope. It reduces the risk of updating
152  * the wrong part of the buffer and having no compiler warning about that. If
153  * the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can warn
154  * about the use of uninitialized variable.
155  */
156 #define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({				\
157 	struct iosys_map copy = *map_;					\
158 	iosys_map_incr(&copy, offset_);					\
159 	copy;								\
160 })
161 
162 /**
163  * iosys_map_set_vaddr - Sets a iosys mapping structure to an address in system memory
164  * @map:	The iosys_map structure
165  * @vaddr:	A system-memory address
166  *
167  * Sets the address and clears the I/O-memory flag.
168  */
iosys_map_set_vaddr(struct iosys_map * map,void * vaddr)169 static inline void iosys_map_set_vaddr(struct iosys_map *map, void *vaddr)
170 {
171 	map->vaddr = vaddr;
172 	map->is_iomem = false;
173 }
174 
175 /**
176  * iosys_map_set_vaddr_iomem - Sets a iosys mapping structure to an address in I/O memory
177  * @map:		The iosys_map structure
178  * @vaddr_iomem:	An I/O-memory address
179  *
180  * Sets the address and the I/O-memory flag.
181  */
iosys_map_set_vaddr_iomem(struct iosys_map * map,void __iomem * vaddr_iomem)182 static inline void iosys_map_set_vaddr_iomem(struct iosys_map *map,
183 					     void __iomem *vaddr_iomem)
184 {
185 	map->vaddr_iomem = vaddr_iomem;
186 	map->is_iomem = true;
187 }
188 
189 /**
190  * iosys_map_is_equal - Compares two iosys mapping structures for equality
191  * @lhs:	The iosys_map structure
192  * @rhs:	A iosys_map structure to compare with
193  *
194  * Two iosys mapping structures are equal if they both refer to the same type of memory
195  * and to the same address within that memory.
196  *
197  * Returns:
198  * True is both structures are equal, or false otherwise.
199  */
iosys_map_is_equal(const struct iosys_map * lhs,const struct iosys_map * rhs)200 static inline bool iosys_map_is_equal(const struct iosys_map *lhs,
201 				      const struct iosys_map *rhs)
202 {
203 	if (lhs->is_iomem != rhs->is_iomem)
204 		return false;
205 	else if (lhs->is_iomem)
206 		return lhs->vaddr_iomem == rhs->vaddr_iomem;
207 	else
208 		return lhs->vaddr == rhs->vaddr;
209 }
210 
211 /**
212  * iosys_map_is_null - Tests for a iosys mapping to be NULL
213  * @map:	The iosys_map structure
214  *
215  * Depending on the state of struct iosys_map.is_iomem, tests if the
216  * mapping is NULL.
217  *
218  * Returns:
219  * True if the mapping is NULL, or false otherwise.
220  */
iosys_map_is_null(const struct iosys_map * map)221 static inline bool iosys_map_is_null(const struct iosys_map *map)
222 {
223 	if (map->is_iomem)
224 		return !map->vaddr_iomem;
225 	return !map->vaddr;
226 }
227 
228 /**
229  * iosys_map_is_set - Tests if the iosys mapping has been set
230  * @map:	The iosys_map structure
231  *
232  * Depending on the state of struct iosys_map.is_iomem, tests if the
233  * mapping has been set.
234  *
235  * Returns:
236  * True if the mapping is been set, or false otherwise.
237  */
iosys_map_is_set(const struct iosys_map * map)238 static inline bool iosys_map_is_set(const struct iosys_map *map)
239 {
240 	return !iosys_map_is_null(map);
241 }
242 
243 /**
244  * iosys_map_clear - Clears a iosys mapping structure
245  * @map:	The iosys_map structure
246  *
247  * Clears all fields to zero, including struct iosys_map.is_iomem, so
248  * mapping structures that were set to point to I/O memory are reset for
249  * system memory. Pointers are cleared to NULL. This is the default.
250  */
iosys_map_clear(struct iosys_map * map)251 static inline void iosys_map_clear(struct iosys_map *map)
252 {
253 	if (map->is_iomem) {
254 		map->vaddr_iomem = NULL;
255 		map->is_iomem = false;
256 	} else {
257 		map->vaddr = NULL;
258 	}
259 }
260 
261 /**
262  * iosys_map_memcpy_to - Memcpy into offset of iosys_map
263  * @dst:	The iosys_map structure
264  * @dst_offset:	The offset from which to copy
265  * @src:	The source buffer
266  * @len:	The number of byte in src
267  *
268  * Copies data into a iosys_map with an offset. The source buffer is in
269  * system memory. Depending on the buffer's location, the helper picks the
270  * correct method of accessing the memory.
271  */
iosys_map_memcpy_to(struct iosys_map * dst,size_t dst_offset,const void * src,size_t len)272 static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset,
273 				       const void *src, size_t len)
274 {
275 	if (dst->is_iomem)
276 		memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
277 	else
278 		memcpy(dst->vaddr + dst_offset, src, len);
279 }
280 
281 /**
282  * iosys_map_memcpy_from - Memcpy from iosys_map into system memory
283  * @dst:	Destination in system memory
284  * @src:	The iosys_map structure
285  * @src_offset:	The offset from which to copy
286  * @len:	The number of byte in src
287  *
288  * Copies data from a iosys_map with an offset. The dest buffer is in
289  * system memory. Depending on the mapping location, the helper picks the
290  * correct method of accessing the memory.
291  */
iosys_map_memcpy_from(void * dst,const struct iosys_map * src,size_t src_offset,size_t len)292 static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map *src,
293 					 size_t src_offset, size_t len)
294 {
295 	if (src->is_iomem)
296 		memcpy_fromio(dst, src->vaddr_iomem + src_offset, len);
297 	else
298 		memcpy(dst, src->vaddr + src_offset, len);
299 }
300 
301 /**
302  * iosys_map_incr - Increments the address stored in a iosys mapping
303  * @map:	The iosys_map structure
304  * @incr:	The number of bytes to increment
305  *
306  * Increments the address stored in a iosys mapping. Depending on the
307  * buffer's location, the correct value will be updated.
308  */
iosys_map_incr(struct iosys_map * map,size_t incr)309 static inline void iosys_map_incr(struct iosys_map *map, size_t incr)
310 {
311 	if (map->is_iomem)
312 		map->vaddr_iomem += incr;
313 	else
314 		map->vaddr += incr;
315 }
316 
317 /**
318  * iosys_map_memset - Memset iosys_map
319  * @dst:	The iosys_map structure
320  * @offset:	Offset from dst where to start setting value
321  * @value:	The value to set
322  * @len:	The number of bytes to set in dst
323  *
324  * Set value in iosys_map. Depending on the buffer's location, the helper
325  * picks the correct method of accessing the memory.
326  */
iosys_map_memset(struct iosys_map * dst,size_t offset,int value,size_t len)327 static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
328 				    int value, size_t len)
329 {
330 	if (dst->is_iomem)
331 		memset_io(dst->vaddr_iomem + offset, value, len);
332 	else
333 		memset(dst->vaddr + offset, value, len);
334 }
335 
336 /**
337  * iosys_map_rd - Read a C-type value from the iosys_map
338  *
339  * @map__:	The iosys_map structure
340  * @offset__:	The offset from which to read
341  * @type__:	Type of the value being read
342  *
343  * Read a C type value from iosys_map, handling possible un-aligned accesses to
344  * the mapping.
345  *
346  * Returns:
347  * The value read from the mapping.
348  */
349 #define iosys_map_rd(map__, offset__, type__) ({			\
350 	type__ val;							\
351 	iosys_map_memcpy_from(&val, map__, offset__, sizeof(val));	\
352 	val;								\
353 })
354 
355 /**
356  * iosys_map_wr - Write a C-type value to the iosys_map
357  *
358  * @map__:	The iosys_map structure
359  * @offset__:	The offset from the mapping to write to
360  * @type__:	Type of the value being written
361  * @val__:	Value to write
362  *
363  * Write a C-type value to the iosys_map, handling possible un-aligned accesses
364  * to the mapping.
365  */
366 #define iosys_map_wr(map__, offset__, type__, val__) ({			\
367 	type__ val = (val__);						\
368 	iosys_map_memcpy_to(map__, offset__, &val, sizeof(val));	\
369 })
370 
371 /**
372  * iosys_map_rd_field - Read a member from a struct in the iosys_map
373  *
374  * @map__:		The iosys_map structure
375  * @struct_offset__:	Offset from the beggining of the map, where the struct
376  *			is located
377  * @struct_type__:	The struct describing the layout of the mapping
378  * @field__:		Member of the struct to read
379  *
380  * Read a value from iosys_map considering its layout is described by a C struct
381  * starting at @struct_offset__. The field offset and size is calculated and its
382  * value read handling possible un-aligned memory accesses. For example: suppose
383  * there is a @struct foo defined as below and the value ``foo.field2.inner2``
384  * needs to be read from the iosys_map:
385  *
386  * .. code-block:: c
387  *
388  *	struct foo {
389  *		int field1;
390  *		struct {
391  *			int inner1;
392  *			int inner2;
393  *		} field2;
394  *		int field3;
395  *	} __packed;
396  *
397  * This is the expected memory layout of a buffer using iosys_map_rd_field():
398  *
399  * +------------------------------+--------------------------+
400  * | Address                      | Content                  |
401  * +==============================+==========================+
402  * | buffer + 0000                | start of mmapped buffer  |
403  * |                              | pointed by iosys_map     |
404  * +------------------------------+--------------------------+
405  * | ...                          | ...                      |
406  * +------------------------------+--------------------------+
407  * | buffer + ``struct_offset__`` | start of ``struct foo``  |
408  * +------------------------------+--------------------------+
409  * | ...                          | ...                      |
410  * +------------------------------+--------------------------+
411  * | buffer + wwww                | ``foo.field2.inner2``    |
412  * +------------------------------+--------------------------+
413  * | ...                          | ...                      |
414  * +------------------------------+--------------------------+
415  * | buffer + yyyy                | end of ``struct foo``    |
416  * +------------------------------+--------------------------+
417  * | ...                          | ...                      |
418  * +------------------------------+--------------------------+
419  * | buffer + zzzz                | end of mmaped buffer     |
420  * +------------------------------+--------------------------+
421  *
422  * Values automatically calculated by this macro or not needed are denoted by
423  * wwww, yyyy and zzzz. This is the code to read that value:
424  *
425  * .. code-block:: c
426  *
427  *	x = iosys_map_rd_field(&map, offset, struct foo, field2.inner2);
428  *
429  * Returns:
430  * The value read from the mapping.
431  */
432 #define iosys_map_rd_field(map__, struct_offset__, struct_type__, field__) ({	\
433 	struct_type__ *s;							\
434 	iosys_map_rd(map__, struct_offset__ + offsetof(struct_type__, field__),	\
435 		     typeof(s->field__));					\
436 })
437 
438 /**
439  * iosys_map_wr_field - Write to a member of a struct in the iosys_map
440  *
441  * @map__:		The iosys_map structure
442  * @struct_offset__:	Offset from the beggining of the map, where the struct
443  *			is located
444  * @struct_type__:	The struct describing the layout of the mapping
445  * @field__:		Member of the struct to read
446  * @val__:		Value to write
447  *
448  * Write a value to the iosys_map considering its layout is described by a C struct
449  * starting at @struct_offset__. The field offset and size is calculated and the
450  * @val__ is written handling possible un-aligned memory accesses. Refer to
451  * iosys_map_rd_field() for expected usage and memory layout.
452  */
453 #define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({	\
454 	struct_type__ *s;								\
455 	iosys_map_wr(map__, struct_offset__ + offsetof(struct_type__, field__),		\
456 		     typeof(s->field__), val__);					\
457 })
458 
459 #endif /* __IOSYS_MAP_H__ */
460