iosys-map: Add a few more helpers
First the simplest ones: - iosys_map_memset(): when abstracting system and I/O memory, just like the memcpy() use case, memset() also has dedicated functions to be called for using IO memory. - iosys_map_memcpy_from(): we may need to copy data from I/O memory, not only to. In certain situations it's useful to be able to read or write to an offset that is calculated by having the memory layout given by a struct declaration. Usually we are going to read/write a u8, u16, u32 or u64. As a pre-requisite for the implementation, add iosys_map_memcpy_from() to be the equivalent of iosys_map_memcpy_to(), but in the other direction. Then add 2 pairs of macros: - iosys_map_rd() / iosys_map_wr() - iosys_map_rd_field() / iosys_map_wr_field() The first pair takes the C-type and offset to read/write. The second pair uses a struct describing the layout of the mapping in order to calculate the offset and size being read/written. We could use readb, readw, readl, readq and the write* counterparts, however due to alignment issues this may not work on all architectures. If alignment needs to be checked to call the right function, it's not possible to decide at compile-time which function to call: so just leave the decision to the memcpy function that will do exactly that. Finally, in order to use the above macros with a map derived from another, add another initializer: IOSYS_MAP_INIT_OFFSET(). v2: - Rework IOSYS_MAP_INIT_OFFSET() so it doesn't rely on aliasing rules within the union - Add offset to both iosys_map_rd_field() and iosys_map_wr_field() to allow the struct itself to be at an offset from the mapping - Add documentation to iosys_map_rd_field() with example and expected memory layout v3: - Drop kernel.h include as it's not needed anymore Cc: Sumit Semwal <sumit.semwal@linaro.org> Cc: Christian König <christian.koenig@amd.com> Cc: Thomas Zimmermann <tzimmermann@suse.de> Cc: Mauro Carvalho Chehab <mchehab@kernel.org> Cc: dri-devel@lists.freedesktop.org Cc: linux-kernel@vger.kernel.org Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com> Reviewed-by: Mauro Carvalho Chehab <mchehab@kernel.org> Reviewed-by: Matt Atwood <matthew.s.atwood@intel.com> Reviewed-by: Thomas Zimmermann <tzimmermann@suse.de> Link: https://patchwork.freedesktop.org/patch/msgid/20220216174147.3073235-3-lucas.demarchi@intel.com
This commit is contained in:
parent
cccd73d607
commit
e62f25e8b3
@ -120,6 +120,45 @@ struct iosys_map {
|
||||
.is_iomem = false, \
|
||||
}
|
||||
|
||||
/**
|
||||
* IOSYS_MAP_INIT_OFFSET - Initializes struct iosys_map from another iosys_map
|
||||
* @map_: The dma-buf mapping structure to copy from
|
||||
* @offset_: Offset to add to the other mapping
|
||||
*
|
||||
* Initializes a new iosys_map struct based on another passed as argument. It
|
||||
* does a shallow copy of the struct so it's possible to update the back storage
|
||||
* without changing where the original map points to. It is the equivalent of
|
||||
* doing:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* iosys_map map = other_map;
|
||||
* iosys_map_incr(&map, &offset);
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* void foo(struct device *dev, struct iosys_map *base_map)
|
||||
* {
|
||||
* ...
|
||||
* struct iosys_map map = IOSYS_MAP_INIT_OFFSET(base_map, FIELD_OFFSET);
|
||||
* ...
|
||||
* }
|
||||
*
|
||||
* The advantage of using the initializer over just increasing the offset with
|
||||
* iosys_map_incr() like above is that the new map will always point to the
|
||||
* right place of the buffer during its scope. It reduces the risk of updating
|
||||
* the wrong part of the buffer and having no compiler warning about that. If
|
||||
* the assignment to IOSYS_MAP_INIT_OFFSET() is forgotten, the compiler can warn
|
||||
* about the use of uninitialized variable.
|
||||
*/
|
||||
#define IOSYS_MAP_INIT_OFFSET(map_, offset_) ({ \
|
||||
struct iosys_map copy = *map_; \
|
||||
iosys_map_incr(©, offset_); \
|
||||
copy; \
|
||||
})
|
||||
|
||||
/**
|
||||
* iosys_map_set_vaddr - Sets a iosys mapping structure to an address in system memory
|
||||
* @map: The iosys_map structure
|
||||
@ -239,6 +278,26 @@ static inline void iosys_map_memcpy_to(struct iosys_map *dst, size_t dst_offset,
|
||||
memcpy(dst->vaddr + dst_offset, src, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* iosys_map_memcpy_from - Memcpy from iosys_map into system memory
|
||||
* @dst: Destination in system memory
|
||||
* @src: The iosys_map structure
|
||||
* @src_offset: The offset from which to copy
|
||||
* @len: The number of byte in src
|
||||
*
|
||||
* Copies data from a iosys_map with an offset. The dest buffer is in
|
||||
* system memory. Depending on the mapping location, the helper picks the
|
||||
* correct method of accessing the memory.
|
||||
*/
|
||||
static inline void iosys_map_memcpy_from(void *dst, const struct iosys_map *src,
|
||||
size_t src_offset, size_t len)
|
||||
{
|
||||
if (src->is_iomem)
|
||||
memcpy_fromio(dst, src->vaddr_iomem + src_offset, len);
|
||||
else
|
||||
memcpy(dst, src->vaddr + src_offset, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* iosys_map_incr - Increments the address stored in a iosys mapping
|
||||
* @map: The iosys_map structure
|
||||
@ -255,4 +314,146 @@ static inline void iosys_map_incr(struct iosys_map *map, size_t incr)
|
||||
map->vaddr += incr;
|
||||
}
|
||||
|
||||
/**
|
||||
* iosys_map_memset - Memset iosys_map
|
||||
* @dst: The iosys_map structure
|
||||
* @offset: Offset from dst where to start setting value
|
||||
* @value: The value to set
|
||||
* @len: The number of bytes to set in dst
|
||||
*
|
||||
* Set value in iosys_map. Depending on the buffer's location, the helper
|
||||
* picks the correct method of accessing the memory.
|
||||
*/
|
||||
static inline void iosys_map_memset(struct iosys_map *dst, size_t offset,
|
||||
int value, size_t len)
|
||||
{
|
||||
if (dst->is_iomem)
|
||||
memset_io(dst->vaddr_iomem + offset, value, len);
|
||||
else
|
||||
memset(dst->vaddr + offset, value, len);
|
||||
}
|
||||
|
||||
/**
|
||||
* iosys_map_rd - Read a C-type value from the iosys_map
|
||||
*
|
||||
* @map__: The iosys_map structure
|
||||
* @offset__: The offset from which to read
|
||||
* @type__: Type of the value being read
|
||||
*
|
||||
* Read a C type value from iosys_map, handling possible un-aligned accesses to
|
||||
* the mapping.
|
||||
*
|
||||
* Returns:
|
||||
* The value read from the mapping.
|
||||
*/
|
||||
#define iosys_map_rd(map__, offset__, type__) ({ \
|
||||
type__ val; \
|
||||
iosys_map_memcpy_from(&val, map__, offset__, sizeof(val)); \
|
||||
val; \
|
||||
})
|
||||
|
||||
/**
|
||||
* iosys_map_wr - Write a C-type value to the iosys_map
|
||||
*
|
||||
* @map__: The iosys_map structure
|
||||
* @offset__: The offset from the mapping to write to
|
||||
* @type__: Type of the value being written
|
||||
* @val__: Value to write
|
||||
*
|
||||
* Write a C-type value to the iosys_map, handling possible un-aligned accesses
|
||||
* to the mapping.
|
||||
*/
|
||||
#define iosys_map_wr(map__, offset__, type__, val__) ({ \
|
||||
type__ val = (val__); \
|
||||
iosys_map_memcpy_to(map__, offset__, &val, sizeof(val)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* iosys_map_rd_field - Read a member from a struct in the iosys_map
|
||||
*
|
||||
* @map__: The iosys_map structure
|
||||
* @struct_offset__: Offset from the beggining of the map, where the struct
|
||||
* is located
|
||||
* @struct_type__: The struct describing the layout of the mapping
|
||||
* @field__: Member of the struct to read
|
||||
*
|
||||
* Read a value from iosys_map considering its layout is described by a C struct
|
||||
* starting at @struct_offset__. The field offset and size is calculated and its
|
||||
* value read handling possible un-aligned memory accesses. For example: suppose
|
||||
* there is a @struct foo defined as below and the value ``foo.field2.inner2``
|
||||
* needs to be read from the iosys_map:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* struct foo {
|
||||
* int field1;
|
||||
* struct {
|
||||
* int inner1;
|
||||
* int inner2;
|
||||
* } field2;
|
||||
* int field3;
|
||||
* } __packed;
|
||||
*
|
||||
* This is the expected memory layout of a buffer using iosys_map_rd_field():
|
||||
*
|
||||
* +------------------------------+--------------------------+
|
||||
* | Address | Content |
|
||||
* +==============================+==========================+
|
||||
* | buffer + 0000 | start of mmapped buffer |
|
||||
* | | pointed by iosys_map |
|
||||
* +------------------------------+--------------------------+
|
||||
* | ... | ... |
|
||||
* +------------------------------+--------------------------+
|
||||
* | buffer + ``struct_offset__`` | start of ``struct foo`` |
|
||||
* +------------------------------+--------------------------+
|
||||
* | ... | ... |
|
||||
* +------------------------------+--------------------------+
|
||||
* | buffer + wwww | ``foo.field2.inner2`` |
|
||||
* +------------------------------+--------------------------+
|
||||
* | ... | ... |
|
||||
* +------------------------------+--------------------------+
|
||||
* | buffer + yyyy | end of ``struct foo`` |
|
||||
* +------------------------------+--------------------------+
|
||||
* | ... | ... |
|
||||
* +------------------------------+--------------------------+
|
||||
* | buffer + zzzz | end of mmaped buffer |
|
||||
* +------------------------------+--------------------------+
|
||||
*
|
||||
* Values automatically calculated by this macro or not needed are denoted by
|
||||
* wwww, yyyy and zzzz. This is the code to read that value:
|
||||
*
|
||||
* .. code-block:: c
|
||||
*
|
||||
* x = iosys_map_rd_field(&map, offset, struct foo, field2.inner2);
|
||||
*
|
||||
* Returns:
|
||||
* The value read from the mapping.
|
||||
*/
|
||||
#define iosys_map_rd_field(map__, struct_offset__, struct_type__, field__) ({ \
|
||||
struct_type__ *s; \
|
||||
iosys_map_rd(map__, struct_offset__ + offsetof(struct_type__, field__), \
|
||||
typeof(s->field__)); \
|
||||
})
|
||||
|
||||
/**
|
||||
* iosys_map_wr_field - Write to a member of a struct in the iosys_map
|
||||
*
|
||||
* @map__: The iosys_map structure
|
||||
* @struct_offset__: Offset from the beggining of the map, where the struct
|
||||
* is located
|
||||
* @struct_type__: The struct describing the layout of the mapping
|
||||
* @field__: Member of the struct to read
|
||||
* @val__: Value to write
|
||||
*
|
||||
* Write a value to the iosys_map considering its layout is described by a C struct
|
||||
* starting at @struct_offset__. The field offset and size is calculated and the
|
||||
* @val__ is written handling possible un-aligned memory accesses. Refer to
|
||||
* iosys_map_rd_field() for expected usage and memory layout.
|
||||
*/
|
||||
#define iosys_map_wr_field(map__, struct_offset__, struct_type__, field__, val__) ({ \
|
||||
struct_type__ *s; \
|
||||
iosys_map_wr(map__, struct_offset__ + offsetof(struct_type__, field__), \
|
||||
typeof(s->field__), val__); \
|
||||
})
|
||||
|
||||
#endif /* __IOSYS_MAP_H__ */
|
||||
|
Loading…
x
Reference in New Issue
Block a user