Merge tag 'pull-18-rc1-work.fd' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / include / linux / iosys-map.h
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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  */
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__ */