LCOV - code coverage report
Current view: top level - include/linux - iosys-map.h (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 24 0.0 %
Date: 2022-12-09 01:23:36 Functions: 0 1 0.0 %

          Line data    Source code
       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           0 :         map->vaddr = vaddr;
     172           0 :         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           0 :         map->vaddr_iomem = vaddr_iomem;
     186           0 :         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           0 :         if (lhs->is_iomem != rhs->is_iomem)
     204             :                 return false;
     205           0 :         else if (lhs->is_iomem)
     206           0 :                 return lhs->vaddr_iomem == rhs->vaddr_iomem;
     207             :         else
     208           0 :                 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           0 :         if (map->is_iomem)
     224           0 :                 return !map->vaddr_iomem;
     225           0 :         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           0 :         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           0 :         if (map->is_iomem) {
     254           0 :                 map->vaddr_iomem = NULL;
     255           0 :                 map->is_iomem = false;
     256             :         } else {
     257           0 :                 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           0 : static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset,
     273             :                                        const void *src, size_t len)
     274             : {
     275           0 :         if (dst->is_iomem)
     276           0 :                 memcpy_toio(dst->vaddr_iomem + dst_offset, src, len);
     277             :         else
     278           0 :                 memcpy(dst->vaddr + dst_offset, src, len);
     279           0 : }
     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           0 :         if (map->is_iomem)
     312           0 :                 map->vaddr_iomem += incr;
     313             :         else
     314           0 :                 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__ */

Generated by: LCOV version 1.14