diff mbox series

[01/19] dma-buf-map: Add read/write helpers

Message ID 20220126203702.1784589-2-lucas.demarchi@intel.com (mailing list archive)
State New, archived
Headers show
Series drm/i915/guc: Refactor ADS access to use dma_buf_map | expand

Commit Message

Lucas De Marchi Jan. 26, 2022, 8:36 p.m. UTC
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.

Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
to calculate the offset of a struct member and memcpy the data from/to
the dma_buf_map. 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 on IO memory or dereference the pointer.

Cc: Sumit Semwal <sumit.semwal@linaro.org>
Cc: Christian König <christian.koenig@amd.com>
Cc: linux-media@vger.kernel.org
Cc: dri-devel@lists.freedesktop.org
Cc: linaro-mm-sig@lists.linaro.org
Cc: linux-kernel@vger.kernel.org
Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
---
 include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
 1 file changed, 81 insertions(+)

Comments

Christian König Jan. 27, 2022, 7:24 a.m. UTC | #1
Am 26.01.22 um 21:36 schrieb Lucas De Marchi:
> 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.
>
> Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
> to calculate the offset of a struct member and memcpy the data from/to
> the dma_buf_map. 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 on IO memory or dereference the pointer.
>
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: Christian König <christian.koenig@amd.com>
> Cc: linux-media@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linaro-mm-sig@lists.linaro.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>   include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 81 insertions(+)
>
> diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
> index 19fa0b5ae5ec..65e927d9ce33 100644
> --- a/include/linux/dma-buf-map.h
> +++ b/include/linux/dma-buf-map.h
> @@ -6,6 +6,7 @@
>   #ifndef __DMA_BUF_MAP_H__
>   #define __DMA_BUF_MAP_H__
>   
> +#include <linux/kernel.h>
>   #include <linux/io.h>
>   #include <linux/string.h>
>   
> @@ -229,6 +230,46 @@ static inline void dma_buf_map_clear(struct dma_buf_map *map)
>   	}
>   }
>   
> +/**
> + * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
> + * @dst:	The dma-buf mapping structure
> + * @offset:	The offset from which to copy
> + * @src:	The source buffer
> + * @len:	The number of byte in src
> + *
> + * Copies data into a dma-buf mapping with an offset. The source buffer is in
> + * system memory. Depending on the buffer's location, the helper picks the
> + * correct method of accessing the memory.
> + */
> +static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map *dst, size_t offset,
> +						const void *src, size_t len)
> +{
> +	if (dst->is_iomem)
> +		memcpy_toio(dst->vaddr_iomem + offset, src, len);
> +	else
> +		memcpy(dst->vaddr + offset, src, len);
> +}
> +
> +/**
> + * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf mapping into system memory
> + * @dst:	Destination in system memory
> + * @src:	The dma-buf mapping structure
> + * @src:	The offset from which to copy
> + * @len:	The number of byte in src
> + *
> + * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const struct dma_buf_map *src,
> +						  size_t offset, size_t len)
> +{
> +	if (src->is_iomem)
> +		memcpy_fromio(dst, src->vaddr_iomem + offset, len);
> +	else
> +		memcpy(dst, src->vaddr + offset, len);
> +}
> +

Well that's certainly a valid use case, but I suggest to change the 
implementation of the existing functions to call the new ones with offset=0.

This way we only have one implementation.

>   /**
>    * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
>    * @dst:	The dma-buf mapping structure
> @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
>   		map->vaddr += incr;
>   }
>   
> +/**
> + * dma_buf_map_read_field - Read struct member from dma-buf mapping with
> + * arbitrary size and handling un-aligned accesses
> + *
> + * @map__:	The dma-buf mapping structure
> + * @type__:	The struct to be used containing the field to read
> + * @field__:	Member from struct we want to read
> + *
> + * Read a value from dma-buf mapping calculating the offset and size: this assumes
> + * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
> + * or u64 can be read, based on the offset and size of type__.field__.
> + */
> +#define dma_buf_map_read_field(map__, type__, field__) ({				\
> +	type__ *t__;									\
> +	typeof(t__->field__) val__;							\
> +	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
> +				       sizeof(t__->field__));				\
> +	val__;										\
> +})
> +
> +/**
> + * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
> + * arbitrary size and handling un-aligned accesses
> + *
> + * @map__:	The dma-buf mapping structure
> + * @type__:	The struct to be used containing the field to write
> + * @field__:	Member from struct we want to write
> + * @val__:	Value to be written
> + *
> + * Write a value to the dma-buf mapping calculating the offset and size.
> + * A single u8, u16, u32 or u64 can be written based on the offset and size of
> + * type__.field__.
> + */
> +#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
> +	type__ *t__;									\
> +	typeof(t__->field__) val____ = val__;						\
> +	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
> +				     &val____, sizeof(t__->field__));			\
> +})
> +

Uff well that absolutely looks like overkill to me.

That's a rather special use case as far as I can see and I think we 
should only have this in the common framework if more than one driver is 
using it.

Regards,
Christian.

>   #endif /* __DMA_BUF_MAP_H__ */
Matthew Brost Jan. 27, 2022, 7:36 a.m. UTC | #2
On Thu, Jan 27, 2022 at 08:24:04AM +0100, Christian König wrote:
> Am 26.01.22 um 21:36 schrieb Lucas De Marchi:
> > 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.
> > 
> > Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
> > to calculate the offset of a struct member and memcpy the data from/to
> > the dma_buf_map. 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 on IO memory or dereference the pointer.
> > 
> > Cc: Sumit Semwal <sumit.semwal@linaro.org>
> > Cc: Christian König <christian.koenig@amd.com>
> > Cc: linux-media@vger.kernel.org
> > Cc: dri-devel@lists.freedesktop.org
> > Cc: linaro-mm-sig@lists.linaro.org
> > Cc: linux-kernel@vger.kernel.org
> > Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> > ---
> >   include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
> >   1 file changed, 81 insertions(+)
> > 
> > diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
> > index 19fa0b5ae5ec..65e927d9ce33 100644
> > --- a/include/linux/dma-buf-map.h
> > +++ b/include/linux/dma-buf-map.h
> > @@ -6,6 +6,7 @@
> >   #ifndef __DMA_BUF_MAP_H__
> >   #define __DMA_BUF_MAP_H__
> > +#include <linux/kernel.h>
> >   #include <linux/io.h>
> >   #include <linux/string.h>
> > @@ -229,6 +230,46 @@ static inline void dma_buf_map_clear(struct dma_buf_map *map)
> >   	}
> >   }
> > +/**
> > + * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
> > + * @dst:	The dma-buf mapping structure
> > + * @offset:	The offset from which to copy
> > + * @src:	The source buffer
> > + * @len:	The number of byte in src
> > + *
> > + * Copies data into a dma-buf mapping with an offset. The source buffer is in
> > + * system memory. Depending on the buffer's location, the helper picks the
> > + * correct method of accessing the memory.
> > + */
> > +static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map *dst, size_t offset,
> > +						const void *src, size_t len)
> > +{
> > +	if (dst->is_iomem)
> > +		memcpy_toio(dst->vaddr_iomem + offset, src, len);
> > +	else
> > +		memcpy(dst->vaddr + offset, src, len);
> > +}
> > +
> > +/**
> > + * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf mapping into system memory
> > + * @dst:	Destination in system memory
> > + * @src:	The dma-buf mapping structure
> > + * @src:	The offset from which to copy
> > + * @len:	The number of byte in src
> > + *
> > + * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const struct dma_buf_map *src,
> > +						  size_t offset, size_t len)
> > +{
> > +	if (src->is_iomem)
> > +		memcpy_fromio(dst, src->vaddr_iomem + offset, len);
> > +	else
> > +		memcpy(dst, src->vaddr + offset, len);
> > +}
> > +
> 
> Well that's certainly a valid use case, but I suggest to change the
> implementation of the existing functions to call the new ones with offset=0.
> 
> This way we only have one implementation.
> 
Trivial - but agree with Christian that is a good cleanup.

> >   /**
> >    * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
> >    * @dst:	The dma-buf mapping structure
> > @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
> >   		map->vaddr += incr;
> >   }
> > +/**
> > + * dma_buf_map_read_field - Read struct member from dma-buf mapping with
> > + * arbitrary size and handling un-aligned accesses
> > + *
> > + * @map__:	The dma-buf mapping structure
> > + * @type__:	The struct to be used containing the field to read
> > + * @field__:	Member from struct we want to read
> > + *
> > + * Read a value from dma-buf mapping calculating the offset and size: this assumes
> > + * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
> > + * or u64 can be read, based on the offset and size of type__.field__.
> > + */
> > +#define dma_buf_map_read_field(map__, type__, field__) ({				\
> > +	type__ *t__;									\
> > +	typeof(t__->field__) val__;							\
> > +	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
> > +				       sizeof(t__->field__));				\
> > +	val__;										\
> > +})
> > +
> > +/**
> > + * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
> > + * arbitrary size and handling un-aligned accesses
> > + *
> > + * @map__:	The dma-buf mapping structure
> > + * @type__:	The struct to be used containing the field to write
> > + * @field__:	Member from struct we want to write
> > + * @val__:	Value to be written
> > + *
> > + * Write a value to the dma-buf mapping calculating the offset and size.
> > + * A single u8, u16, u32 or u64 can be written based on the offset and size of
> > + * type__.field__.
> > + */
> > +#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
> > +	type__ *t__;									\
> > +	typeof(t__->field__) val____ = val__;						\
> > +	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
> > +				     &val____, sizeof(t__->field__));			\
> > +})
> > +
> 
> Uff well that absolutely looks like overkill to me.
> 

Hold on...

> That's a rather special use case as far as I can see and I think we should
> only have this in the common framework if more than one driver is using it.
>

I disagree, this is rather elegant.

The i915 can't be the *only* driver that defines a struct which
describes the layout of a dma_buf object.  

IMO this base macro allows *all* other drivers to build on this write
directly to fields in structures those drivers have defined. Patches
later in this series do this for the GuC ads.

Matt
 
> Regards,
> Christian.
> 
> >   #endif /* __DMA_BUF_MAP_H__ */
>
Christian König Jan. 27, 2022, 7:59 a.m. UTC | #3
Am 27.01.22 um 08:36 schrieb Matthew Brost:
> [SNIP]
>>>    /**
>>>     * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
>>>     * @dst:	The dma-buf mapping structure
>>> @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
>>>    		map->vaddr += incr;
>>>    }
>>> +/**
>>> + * dma_buf_map_read_field - Read struct member from dma-buf mapping with
>>> + * arbitrary size and handling un-aligned accesses
>>> + *
>>> + * @map__:	The dma-buf mapping structure
>>> + * @type__:	The struct to be used containing the field to read
>>> + * @field__:	Member from struct we want to read
>>> + *
>>> + * Read a value from dma-buf mapping calculating the offset and size: this assumes
>>> + * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
>>> + * or u64 can be read, based on the offset and size of type__.field__.
>>> + */
>>> +#define dma_buf_map_read_field(map__, type__, field__) ({				\
>>> +	type__ *t__;									\
>>> +	typeof(t__->field__) val__;							\
>>> +	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
>>> +				       sizeof(t__->field__));				\
>>> +	val__;										\
>>> +})
>>> +
>>> +/**
>>> + * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
>>> + * arbitrary size and handling un-aligned accesses
>>> + *
>>> + * @map__:	The dma-buf mapping structure
>>> + * @type__:	The struct to be used containing the field to write
>>> + * @field__:	Member from struct we want to write
>>> + * @val__:	Value to be written
>>> + *
>>> + * Write a value to the dma-buf mapping calculating the offset and size.
>>> + * A single u8, u16, u32 or u64 can be written based on the offset and size of
>>> + * type__.field__.
>>> + */
>>> +#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
>>> +	type__ *t__;									\
>>> +	typeof(t__->field__) val____ = val__;						\
>>> +	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
>>> +				     &val____, sizeof(t__->field__));			\
>>> +})
>>> +
>> Uff well that absolutely looks like overkill to me.
>>
> Hold on...
>
>> That's a rather special use case as far as I can see and I think we should
>> only have this in the common framework if more than one driver is using it.
>>
> I disagree, this is rather elegant.
>
> The i915 can't be the *only* driver that defines a struct which
> describes the layout of a dma_buf object.

That's not the problem, amdgpu as well as nouveau are doing that as 
well. The problem is DMA-buf is a buffer sharing framework between drivers.

In other words which importer is supposed to use this with a DMA-buf 
exported by another device?

> IMO this base macro allows *all* other drivers to build on this write
> directly to fields in structures those drivers have defined.

Exactly that's the point. This is something drivers should absolutely 
*NOT* do.

That are driver internals and it is extremely questionable to move this 
into the common framework.

Regards,
Christian.

>   Patches
> later in this series do this for the GuC ads.
>
> Matt
>   
>> Regards,
>> Christian.
>>
>>>    #endif /* __DMA_BUF_MAP_H__ */
Daniel Vetter Jan. 27, 2022, 9:02 a.m. UTC | #4
On Thu, Jan 27, 2022 at 08:59:36AM +0100, Christian König wrote:
> Am 27.01.22 um 08:36 schrieb Matthew Brost:
> > [SNIP]
> > > >    /**
> > > >     * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
> > > >     * @dst:	The dma-buf mapping structure
> > > > @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
> > > >    		map->vaddr += incr;
> > > >    }
> > > > +/**
> > > > + * dma_buf_map_read_field - Read struct member from dma-buf mapping with
> > > > + * arbitrary size and handling un-aligned accesses
> > > > + *
> > > > + * @map__:	The dma-buf mapping structure
> > > > + * @type__:	The struct to be used containing the field to read
> > > > + * @field__:	Member from struct we want to read
> > > > + *
> > > > + * Read a value from dma-buf mapping calculating the offset and size: this assumes
> > > > + * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
> > > > + * or u64 can be read, based on the offset and size of type__.field__.
> > > > + */
> > > > +#define dma_buf_map_read_field(map__, type__, field__) ({				\
> > > > +	type__ *t__;									\
> > > > +	typeof(t__->field__) val__;							\
> > > > +	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
> > > > +				       sizeof(t__->field__));				\
> > > > +	val__;										\
> > > > +})
> > > > +
> > > > +/**
> > > > + * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
> > > > + * arbitrary size and handling un-aligned accesses
> > > > + *
> > > > + * @map__:	The dma-buf mapping structure
> > > > + * @type__:	The struct to be used containing the field to write
> > > > + * @field__:	Member from struct we want to write
> > > > + * @val__:	Value to be written
> > > > + *
> > > > + * Write a value to the dma-buf mapping calculating the offset and size.
> > > > + * A single u8, u16, u32 or u64 can be written based on the offset and size of
> > > > + * type__.field__.
> > > > + */
> > > > +#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
> > > > +	type__ *t__;									\
> > > > +	typeof(t__->field__) val____ = val__;						\
> > > > +	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
> > > > +				     &val____, sizeof(t__->field__));			\
> > > > +})
> > > > +
> > > Uff well that absolutely looks like overkill to me.
> > > 
> > Hold on...
> > 
> > > That's a rather special use case as far as I can see and I think we should
> > > only have this in the common framework if more than one driver is using it.
> > > 
> > I disagree, this is rather elegant.
> > 
> > The i915 can't be the *only* driver that defines a struct which
> > describes the layout of a dma_buf object.
> 
> That's not the problem, amdgpu as well as nouveau are doing that as well.
> The problem is DMA-buf is a buffer sharing framework between drivers.
> 
> In other words which importer is supposed to use this with a DMA-buf
> exported by another device?
> 
> > IMO this base macro allows *all* other drivers to build on this write
> > directly to fields in structures those drivers have defined.
> 
> Exactly that's the point. This is something drivers should absolutely *NOT*
> do.
> 
> That are driver internals and it is extremely questionable to move this into
> the common framework.

See my other reply.

This is about struct dma_buf_map, which is just a tagged pointer.

Which happens to be used by the dma_buf cross-driver interface, but it's
also used plenty internally in buffer allocation helpers, fbdev,
everything else. And it was _meant_ to be used like that - this thing is
my idea, I know :-)

I guess we could move/rename it, but like I said I really don't have any
good ideas. Got some?
-Daniel
Thomas Zimmermann Jan. 27, 2022, 2:26 p.m. UTC | #5
Hi

Am 26.01.22 um 21:36 schrieb Lucas De Marchi:
> 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.
> 
> Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
> to calculate the offset of a struct member and memcpy the data from/to
> the dma_buf_map. 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 on IO memory or dereference the pointer.
> 
> Cc: Sumit Semwal <sumit.semwal@linaro.org>
> Cc: Christian König <christian.koenig@amd.com>
> Cc: linux-media@vger.kernel.org
> Cc: dri-devel@lists.freedesktop.org
> Cc: linaro-mm-sig@lists.linaro.org
> Cc: linux-kernel@vger.kernel.org
> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
> ---
>   include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
>   1 file changed, 81 insertions(+)
> 
> diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
> index 19fa0b5ae5ec..65e927d9ce33 100644
> --- a/include/linux/dma-buf-map.h
> +++ b/include/linux/dma-buf-map.h
> @@ -6,6 +6,7 @@
>   #ifndef __DMA_BUF_MAP_H__
>   #define __DMA_BUF_MAP_H__
>   
> +#include <linux/kernel.h>
>   #include <linux/io.h>
>   #include <linux/string.h>
>   
> @@ -229,6 +230,46 @@ static inline void dma_buf_map_clear(struct dma_buf_map *map)
>   	}
>   }
>   
> +/**
> + * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
> + * @dst:	The dma-buf mapping structure
> + * @offset:	The offset from which to copy
> + * @src:	The source buffer
> + * @len:	The number of byte in src
> + *
> + * Copies data into a dma-buf mapping with an offset. The source buffer is in
> + * system memory. Depending on the buffer's location, the helper picks the
> + * correct method of accessing the memory.
> + */
> +static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map *dst, size_t offset,
> +						const void *src, size_t len)
> +{
> +	if (dst->is_iomem)
> +		memcpy_toio(dst->vaddr_iomem + offset, src, len);
> +	else
> +		memcpy(dst->vaddr + offset, src, len);
> +}

Please don't add a new function. Rather please add the offset parameter 
to dma_buf_map_memcpy_to() and update the callers. There are only two 
calls to dma_buf_map_memcpy_to() within the kernel. To make it clear 
what the offset applies to, I'd call the parameter 'dst_offset'.

> +
> +/**
> + * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf mapping into system memory
> + * @dst:	Destination in system memory
> + * @src:	The dma-buf mapping structure
> + * @src:	The offset from which to copy
> + * @len:	The number of byte in src
> + *
> + * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const struct dma_buf_map *src,
> +						  size_t offset, size_t len)
> +{
> +	if (src->is_iomem)
> +		memcpy_fromio(dst, src->vaddr_iomem + offset, len);
> +	else
> +		memcpy(dst, src->vaddr + offset, len);
> +}
> +

With the dma_buf_map_memcpy_to() changes, please just call this function 
dma_buf_map_memcpy_from().

>   /**
>    * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
>    * @dst:	The dma-buf mapping structure
> @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
>   		map->vaddr += incr;
>   }
>   
> +/**
> + * dma_buf_map_read_field - Read struct member from dma-buf mapping with
> + * arbitrary size and handling un-aligned accesses
> + *
> + * @map__:	The dma-buf mapping structure
> + * @type__:	The struct to be used containing the field to read
> + * @field__:	Member from struct we want to read
> + *
> + * Read a value from dma-buf mapping calculating the offset and size: this assumes
> + * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
> + * or u64 can be read, based on the offset and size of type__.field__.
> + */
> +#define dma_buf_map_read_field(map__, type__, field__) ({				\
> +	type__ *t__;									\
> +	typeof(t__->field__) val__;							\
> +	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
> +				       sizeof(t__->field__));				\
> +	val__;										\
> +})
> +
> +/**
> + * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
> + * arbitrary size and handling un-aligned accesses
> + *
> + * @map__:	The dma-buf mapping structure
> + * @type__:	The struct to be used containing the field to write
> + * @field__:	Member from struct we want to write
> + * @val__:	Value to be written
> + *
> + * Write a value to the dma-buf mapping calculating the offset and size.
> + * A single u8, u16, u32 or u64 can be written based on the offset and size of
> + * type__.field__.
> + */
> +#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
> +	type__ *t__;									\
> +	typeof(t__->field__) val____ = val__;						\
> +	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
> +				     &val____, sizeof(t__->field__));			\
> +})

As the original author of this file, I feel like this shouldn't be here. 
At least not until we have another driver using that pattern.

Best regards
Thomas

> +
>   #endif /* __DMA_BUF_MAP_H__ */
Lucas De Marchi Jan. 27, 2022, 4:34 p.m. UTC | #6
On Thu, Jan 27, 2022 at 03:26:43PM +0100, Thomas Zimmermann wrote:
>Hi
>
>Am 26.01.22 um 21:36 schrieb Lucas De Marchi:
>>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.
>>
>>Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
>>to calculate the offset of a struct member and memcpy the data from/to
>>the dma_buf_map. 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 on IO memory or dereference the pointer.
>>
>>Cc: Sumit Semwal <sumit.semwal@linaro.org>
>>Cc: Christian König <christian.koenig@amd.com>
>>Cc: linux-media@vger.kernel.org
>>Cc: dri-devel@lists.freedesktop.org
>>Cc: linaro-mm-sig@lists.linaro.org
>>Cc: linux-kernel@vger.kernel.org
>>Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
>>---
>>  include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
>>  1 file changed, 81 insertions(+)
>>
>>diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
>>index 19fa0b5ae5ec..65e927d9ce33 100644
>>--- a/include/linux/dma-buf-map.h
>>+++ b/include/linux/dma-buf-map.h
>>@@ -6,6 +6,7 @@
>>  #ifndef __DMA_BUF_MAP_H__
>>  #define __DMA_BUF_MAP_H__
>>+#include <linux/kernel.h>
>>  #include <linux/io.h>
>>  #include <linux/string.h>
>>@@ -229,6 +230,46 @@ static inline void dma_buf_map_clear(struct dma_buf_map *map)
>>  	}
>>  }
>>+/**
>>+ * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
>>+ * @dst:	The dma-buf mapping structure
>>+ * @offset:	The offset from which to copy
>>+ * @src:	The source buffer
>>+ * @len:	The number of byte in src
>>+ *
>>+ * Copies data into a dma-buf mapping with an offset. The source buffer is in
>>+ * system memory. Depending on the buffer's location, the helper picks the
>>+ * correct method of accessing the memory.
>>+ */
>>+static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map *dst, size_t offset,
>>+						const void *src, size_t len)
>>+{
>>+	if (dst->is_iomem)
>>+		memcpy_toio(dst->vaddr_iomem + offset, src, len);
>>+	else
>>+		memcpy(dst->vaddr + offset, src, len);
>>+}
>
>Please don't add a new function. Rather please add the offset 
>parameter to dma_buf_map_memcpy_to() and update the callers. There are 
>only two calls to dma_buf_map_memcpy_to() within the kernel. To make 
>it clear what the offset applies to, I'd call the parameter 
>'dst_offset'.
>
>>+
>>+/**
>>+ * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf mapping into system memory
>>+ * @dst:	Destination in system memory
>>+ * @src:	The dma-buf mapping structure
>>+ * @src:	The offset from which to copy
>>+ * @len:	The number of byte in src
>>+ *
>>+ * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const struct dma_buf_map *src,
>>+						  size_t offset, size_t len)
>>+{
>>+	if (src->is_iomem)
>>+		memcpy_fromio(dst, src->vaddr_iomem + offset, len);
>>+	else
>>+		memcpy(dst, src->vaddr + offset, len);
>>+}
>>+
>
>With the dma_buf_map_memcpy_to() changes, please just call this 
>function dma_buf_map_memcpy_from().
>
>>  /**
>>   * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
>>   * @dst:	The dma-buf mapping structure
>>@@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
>>  		map->vaddr += incr;
>>  }
>>+/**
>>+ * dma_buf_map_read_field - Read struct member from dma-buf mapping with
>>+ * arbitrary size and handling un-aligned accesses
>>+ *
>>+ * @map__:	The dma-buf mapping structure
>>+ * @type__:	The struct to be used containing the field to read
>>+ * @field__:	Member from struct we want to read
>>+ *
>>+ * Read a value from dma-buf mapping calculating the offset and size: this assumes
>>+ * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
>>+ * or u64 can be read, based on the offset and size of type__.field__.
>>+ */
>>+#define dma_buf_map_read_field(map__, type__, field__) ({				\
>>+	type__ *t__;									\
>>+	typeof(t__->field__) val__;							\
>>+	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
>>+				       sizeof(t__->field__));				\
>>+	val__;										\
>>+})
>>+
>>+/**
>>+ * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
>>+ * arbitrary size and handling un-aligned accesses
>>+ *
>>+ * @map__:	The dma-buf mapping structure
>>+ * @type__:	The struct to be used containing the field to write
>>+ * @field__:	Member from struct we want to write
>>+ * @val__:	Value to be written
>>+ *
>>+ * Write a value to the dma-buf mapping calculating the offset and size.
>>+ * A single u8, u16, u32 or u64 can be written based on the offset and size of
>>+ * type__.field__.
>>+ */
>>+#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
>>+	type__ *t__;									\
>>+	typeof(t__->field__) val____ = val__;						\
>>+	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
>>+				     &val____, sizeof(t__->field__));			\
>>+})
>
>As the original author of this file, I feel like this shouldn't be 
>here. At least not until we have another driver using that pattern.

Let me try to clear out the confusion. Then maybe I can extend
the documentation of this function in v2 if I'm able to convince this is
useful here.

This is not about importer/exporter, having this to work cross-driver.
This is about using dma_buf_map (which we are talking about on renaming
to iosys_map or something else) for inner driver
allocations/abstractions. The abstraction added by iosys_map helps on
sharing the same functions we had before.  And this macro here is very
useful when the buffer is described by a struct layout. Example:

	struct bla {
		struct inner inner1;
		struct inner inner2;
		u32 x, y ,z;
	};

Functions that would previously do:

	struct bla *bla = ...;

	bla->x = 100;
	bla->y = 200;
	bla->inner1.inner_inner_field = 30;

Can do the below, having the system/IO memory abstracted away
(calling it iosys_map here instead of dma_buf_map, hopeful it helps):

	struct iosys_map *map = ...;

	iosys_map_write_field(map, struct bla, x, 100);
	iosys_map_write_field(map, struct bla, y, 200);
	iosys_map_write_field(map, struct bla,
			      inner1.inner_inner_field, 30);

When we are using mostly the same map, the individual drivers can add
quick helpers on top. See the ads_blob_write() added in this series,
which guarantees the map it's working on is always the guc->ads_map,
while reducing verbosity to use the API. From patch
"drm/i915/guc: Add read/write helpers for ADS blob":

#define ads_blob_read(guc_, field_)                                    \
        dma_buf_map_read_field(&(guc_)->ads_map, struct __guc_ads_blob, \
                               field_)

#define ads_blob_write(guc_, field_, val_)                             \
        dma_buf_map_write_field(&(guc_)->ads_map, struct __guc_ads_blob,\
                                field_, val_)

So in intel_guc_ads, we can have a lot of:

-	bla->x = 100;
+	ads_blob_write(guc, x, 10);

thanks
Lucas De Marchi
Thomas Zimmermann Jan. 28, 2022, 8:32 a.m. UTC | #7
Hi

Am 27.01.22 um 17:34 schrieb Lucas De Marchi:
> On Thu, Jan 27, 2022 at 03:26:43PM +0100, Thomas Zimmermann wrote:
>> Hi
>>
>> Am 26.01.22 um 21:36 schrieb Lucas De Marchi:
>>> 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.
>>>
>>> Add a pair of macros dma_buf_map_read_field()/dma_buf_map_write_field()
>>> to calculate the offset of a struct member and memcpy the data from/to
>>> the dma_buf_map. 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 on IO memory or dereference the pointer.
>>>
>>> Cc: Sumit Semwal <sumit.semwal@linaro.org>
>>> Cc: Christian König <christian.koenig@amd.com>
>>> Cc: linux-media@vger.kernel.org
>>> Cc: dri-devel@lists.freedesktop.org
>>> Cc: linaro-mm-sig@lists.linaro.org
>>> Cc: linux-kernel@vger.kernel.org
>>> Signed-off-by: Lucas De Marchi <lucas.demarchi@intel.com>
>>> ---
>>>  include/linux/dma-buf-map.h | 81 +++++++++++++++++++++++++++++++++++++
>>>  1 file changed, 81 insertions(+)
>>>
>>> diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
>>> index 19fa0b5ae5ec..65e927d9ce33 100644
>>> --- a/include/linux/dma-buf-map.h
>>> +++ b/include/linux/dma-buf-map.h
>>> @@ -6,6 +6,7 @@
>>>  #ifndef __DMA_BUF_MAP_H__
>>>  #define __DMA_BUF_MAP_H__
>>> +#include <linux/kernel.h>
>>>  #include <linux/io.h>
>>>  #include <linux/string.h>
>>> @@ -229,6 +230,46 @@ static inline void dma_buf_map_clear(struct 
>>> dma_buf_map *map)
>>>      }
>>>  }
>>> +/**
>>> + * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
>>> + * @dst:    The dma-buf mapping structure
>>> + * @offset:    The offset from which to copy
>>> + * @src:    The source buffer
>>> + * @len:    The number of byte in src
>>> + *
>>> + * Copies data into a dma-buf mapping with an offset. The source 
>>> buffer is in
>>> + * system memory. Depending on the buffer's location, the helper 
>>> picks the
>>> + * correct method of accessing the memory.
>>> + */
>>> +static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map 
>>> *dst, size_t offset,
>>> +                        const void *src, size_t len)
>>> +{
>>> +    if (dst->is_iomem)
>>> +        memcpy_toio(dst->vaddr_iomem + offset, src, len);
>>> +    else
>>> +        memcpy(dst->vaddr + offset, src, len);
>>> +}
>>
>> Please don't add a new function. Rather please add the offset 
>> parameter to dma_buf_map_memcpy_to() and update the callers. There are 
>> only two calls to dma_buf_map_memcpy_to() within the kernel. To make 
>> it clear what the offset applies to, I'd call the parameter 'dst_offset'.
>>
>>> +
>>> +/**
>>> + * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf 
>>> mapping into system memory
>>> + * @dst:    Destination in system memory
>>> + * @src:    The dma-buf mapping structure
>>> + * @src:    The offset from which to copy
>>> + * @len:    The number of byte in src
>>> + *
>>> + * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const 
>>> struct dma_buf_map *src,
>>> +                          size_t offset, size_t len)
>>> +{
>>> +    if (src->is_iomem)
>>> +        memcpy_fromio(dst, src->vaddr_iomem + offset, len);
>>> +    else
>>> +        memcpy(dst, src->vaddr + offset, len);
>>> +}
>>> +
>>
>> With the dma_buf_map_memcpy_to() changes, please just call this 
>> function dma_buf_map_memcpy_from().
>>
>>>  /**
>>>   * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
>>>   * @dst:    The dma-buf mapping structure
>>> @@ -263,4 +304,44 @@ static inline void dma_buf_map_incr(struct 
>>> dma_buf_map *map, size_t incr)
>>>          map->vaddr += incr;
>>>  }
>>> +/**
>>> + * dma_buf_map_read_field - Read struct member from dma-buf mapping 
>>> with
>>> + * arbitrary size and handling un-aligned accesses
>>> + *
>>> + * @map__:    The dma-buf mapping structure
>>> + * @type__:    The struct to be used containing the field to read
>>> + * @field__:    Member from struct we want to read
>>> + *
>>> + * Read a value from dma-buf mapping calculating the offset and 
>>> size: this assumes
>>> + * the dma-buf mapping is aligned with a a struct type__. A single 
>>> u8, u16, u32
>>> + * or u64 can be read, based on the offset and size of type__.field__.
>>> + */
>>> +#define dma_buf_map_read_field(map__, type__, field__) 
>>> ({                \
>>> +    type__ *t__;                                    \
>>> +    typeof(t__->field__) val__;                            \
>>> +    dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, 
>>> field__),    \
>>> +                       sizeof(t__->field__));                \
>>> +    val__;                                        \
>>> +})
>>> +
>>> +/**
>>> + * dma_buf_map_write_field - Write struct member to the dma-buf 
>>> mapping with
>>> + * arbitrary size and handling un-aligned accesses
>>> + *
>>> + * @map__:    The dma-buf mapping structure
>>> + * @type__:    The struct to be used containing the field to write
>>> + * @field__:    Member from struct we want to write
>>> + * @val__:    Value to be written
>>> + *
>>> + * Write a value to the dma-buf mapping calculating the offset and 
>>> size.
>>> + * A single u8, u16, u32 or u64 can be written based on the offset 
>>> and size of
>>> + * type__.field__.
>>> + */
>>> +#define dma_buf_map_write_field(map__, type__, field__, val__) 
>>> ({            \
>>> +    type__ *t__;                                    \
>>> +    typeof(t__->field__) val____ = val__;                        \
>>> +    dma_buf_map_memcpy_to_offset(map__, offsetof(type__, 
>>> field__),            \
>>> +                     &val____, sizeof(t__->field__));            \
>>> +})
>>
>> As the original author of this file, I feel like this shouldn't be 
>> here. At least not until we have another driver using that pattern.
> 
> Let me try to clear out the confusion. Then maybe I can extend
> the documentation of this function in v2 if I'm able to convince this is
> useful here.
> 
> This is not about importer/exporter, having this to work cross-driver.
> This is about using dma_buf_map (which we are talking about on renaming
> to iosys_map or something else) for inner driver
> allocations/abstractions. The abstraction added by iosys_map helps on
> sharing the same functions we had before.  And this macro here is very
> useful when the buffer is described by a struct layout. Example:
> 
>      struct bla {
>          struct inner inner1;
>          struct inner inner2;
>          u32 x, y ,z;
>      };
> 
> Functions that would previously do:
> 
>      struct bla *bla = ...;
> 
>      bla->x = 100;
>      bla->y = 200;
>      bla->inner1.inner_inner_field = 30;
> 
> Can do the below, having the system/IO memory abstracted away
> (calling it iosys_map here instead of dma_buf_map, hopeful it helps):
> 
>      struct iosys_map *map = ...;

Please don't start renaming anything here. If we want to do this, let's 
have a separate mail thread for coloring the bike shed.

> 
>      iosys_map_write_field(map, struct bla, x, 100);
>      iosys_map_write_field(map, struct bla, y, 200);
>      iosys_map_write_field(map, struct bla,
>                    inner1.inner_inner_field, 30);

I don't have strong feelings about these macros. They just seemed not 
needed in general. But I we want to add them here, I 'd like to propose 
a few small changes.

Again, please add an offset parameter for the map's pointer.

Then I'd call them either dma_buf_map_rd/dma_buf_map_wr for read/write 
OR dma_buf_map_ld/dma_buf_map_st for load/store. They should take a C 
type. Something like this

   dma_buf_map_wr(map, offset, int32, 0x01234);
   val = dam_buf_map_rd(map, offset, int32);

Hopefully, that's flexible enough for all users. On top of that, you can 
build additional helpers like dma_buf_map_rd_field() and 
dma_buf_map_wr_field().

Ok?

Best regards
Thomas

> 
> When we are using mostly the same map, the individual drivers can add
> quick helpers on top. See the ads_blob_write() added in this series,
> which guarantees the map it's working on is always the guc->ads_map,
> while reducing verbosity to use the API. From patch
> "drm/i915/guc: Add read/write helpers for ADS blob":
> 
> #define ads_blob_read(guc_, field_)                                    \
>         dma_buf_map_read_field(&(guc_)->ads_map, struct __guc_ads_blob, \
>                                field_)
> 
> #define ads_blob_write(guc_, field_, val_)                             \
>         dma_buf_map_write_field(&(guc_)->ads_map, struct __guc_ads_blob,\
>                                 field_, val_)
> 
> So in intel_guc_ads, we can have a lot of:
> 
> -    bla->x = 100;
> +    ads_blob_write(guc, x, 10);
> 
> thanks
> Lucas De Marchi
diff mbox series

Patch

diff --git a/include/linux/dma-buf-map.h b/include/linux/dma-buf-map.h
index 19fa0b5ae5ec..65e927d9ce33 100644
--- a/include/linux/dma-buf-map.h
+++ b/include/linux/dma-buf-map.h
@@ -6,6 +6,7 @@ 
 #ifndef __DMA_BUF_MAP_H__
 #define __DMA_BUF_MAP_H__
 
+#include <linux/kernel.h>
 #include <linux/io.h>
 #include <linux/string.h>
 
@@ -229,6 +230,46 @@  static inline void dma_buf_map_clear(struct dma_buf_map *map)
 	}
 }
 
+/**
+ * dma_buf_map_memcpy_to_offset - Memcpy into offset of dma-buf mapping
+ * @dst:	The dma-buf mapping structure
+ * @offset:	The offset from which to copy
+ * @src:	The source buffer
+ * @len:	The number of byte in src
+ *
+ * Copies data into a dma-buf mapping with an offset. The source buffer is in
+ * system memory. Depending on the buffer's location, the helper picks the
+ * correct method of accessing the memory.
+ */
+static inline void dma_buf_map_memcpy_to_offset(struct dma_buf_map *dst, size_t offset,
+						const void *src, size_t len)
+{
+	if (dst->is_iomem)
+		memcpy_toio(dst->vaddr_iomem + offset, src, len);
+	else
+		memcpy(dst->vaddr + offset, src, len);
+}
+
+/**
+ * dma_buf_map_memcpy_from_offset - Memcpy from offset of dma-buf mapping into system memory
+ * @dst:	Destination in system memory
+ * @src:	The dma-buf mapping structure
+ * @src:	The offset from which to copy
+ * @len:	The number of byte in src
+ *
+ * Copies data from a dma-buf mapping 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 dma_buf_map_memcpy_from_offset(void *dst, const struct dma_buf_map *src,
+						  size_t offset, size_t len)
+{
+	if (src->is_iomem)
+		memcpy_fromio(dst, src->vaddr_iomem + offset, len);
+	else
+		memcpy(dst, src->vaddr + offset, len);
+}
+
 /**
  * dma_buf_map_memcpy_to - Memcpy into dma-buf mapping
  * @dst:	The dma-buf mapping structure
@@ -263,4 +304,44 @@  static inline void dma_buf_map_incr(struct dma_buf_map *map, size_t incr)
 		map->vaddr += incr;
 }
 
+/**
+ * dma_buf_map_read_field - Read struct member from dma-buf mapping with
+ * arbitrary size and handling un-aligned accesses
+ *
+ * @map__:	The dma-buf mapping structure
+ * @type__:	The struct to be used containing the field to read
+ * @field__:	Member from struct we want to read
+ *
+ * Read a value from dma-buf mapping calculating the offset and size: this assumes
+ * the dma-buf mapping is aligned with a a struct type__. A single u8, u16, u32
+ * or u64 can be read, based on the offset and size of type__.field__.
+ */
+#define dma_buf_map_read_field(map__, type__, field__) ({				\
+	type__ *t__;									\
+	typeof(t__->field__) val__;							\
+	dma_buf_map_memcpy_from_offset(&val__, map__, offsetof(type__, field__),	\
+				       sizeof(t__->field__));				\
+	val__;										\
+})
+
+/**
+ * dma_buf_map_write_field - Write struct member to the dma-buf mapping with
+ * arbitrary size and handling un-aligned accesses
+ *
+ * @map__:	The dma-buf mapping structure
+ * @type__:	The struct to be used containing the field to write
+ * @field__:	Member from struct we want to write
+ * @val__:	Value to be written
+ *
+ * Write a value to the dma-buf mapping calculating the offset and size.
+ * A single u8, u16, u32 or u64 can be written based on the offset and size of
+ * type__.field__.
+ */
+#define dma_buf_map_write_field(map__, type__, field__, val__) ({			\
+	type__ *t__;									\
+	typeof(t__->field__) val____ = val__;						\
+	dma_buf_map_memcpy_to_offset(map__, offsetof(type__, field__),			\
+				     &val____, sizeof(t__->field__));			\
+})
+
 #endif /* __DMA_BUF_MAP_H__ */