Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4aa806b7 authored by Russell King's avatar Russell King
Browse files

DMA-API: provide a helper to set both DMA and coherent DMA masks



Provide a helper to set both the DMA and coherent DMA masks to the
same value - this avoids duplicated code in a number of drivers,
sometimes with buggy error handling, and also allows us identify
which drivers do things differently.

Signed-off-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
parent 272b98c6
Loading
Loading
Loading
Loading
+22 −15
Original line number Diff line number Diff line
@@ -101,12 +101,21 @@ style to do this even if your device holds the default setting,
because this shows that you did think about these issues wrt. your
device.

The query is performed via a call to dma_set_mask():
The query is performed via a call to dma_set_mask_and_coherent():

	int dma_set_mask_and_coherent(struct device *dev, u64 mask);

which will query the mask for both streaming and coherent APIs together.
If you have some special requirements, then the following two separate
queries can be used instead:

	The query for streaming mappings is performed via a call to
	dma_set_mask():

		int dma_set_mask(struct device *dev, u64 mask);

The query for consistent allocations is performed via a call to
dma_set_coherent_mask():
	The query for consistent allocations is performed via a call
	to dma_set_coherent_mask():

		int dma_set_coherent_mask(struct device *dev, u64 mask);

@@ -137,7 +146,7 @@ exactly why.

The standard 32-bit addressing device would do something like this:

	if (dma_set_mask(dev, DMA_BIT_MASK(32))) {
	if (dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
		printk(KERN_WARNING
		       "mydev: No suitable DMA available.\n");
		goto ignore_this_device;
@@ -171,22 +180,20 @@ the case would look like this:

	int using_dac, consistent_using_dac;

	if (!dma_set_mask(dev, DMA_BIT_MASK(64))) {
	if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64))) {
		using_dac = 1;
	   	consistent_using_dac = 1;
		dma_set_coherent_mask(dev, DMA_BIT_MASK(64));
	} else if (!dma_set_mask(dev, DMA_BIT_MASK(32))) {
	} else if (!dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32))) {
		using_dac = 0;
		consistent_using_dac = 0;
		dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
	} else {
		printk(KERN_WARNING
		       "mydev: No suitable DMA available.\n");
		goto ignore_this_device;
	}

dma_set_coherent_mask() will always be able to set the same or a
smaller mask as dma_set_mask(). However for the rare case that a
The coherent coherent mask will always be able to set the same or a
smaller mask as the streaming mask. However for the rare case that a
device driver only uses consistent allocations, one would have to
check the return value from dma_set_coherent_mask().

@@ -199,9 +206,9 @@ address you might do something like:
		goto ignore_this_device;
	}

When dma_set_mask() is successful, and returns zero, the kernel saves
away this mask you have provided.  The kernel will use this
information later when you make DMA mappings.
When dma_set_mask() or dma_set_mask_and_coherent() is successful, and
returns zero, the kernel saves away this mask you have provided.  The
kernel will use this information later when you make DMA mappings.

There is a case which we are aware of at this time, which is worth
mentioning in this documentation.  If your device supports multiple
+8 −0
Original line number Diff line number Diff line
@@ -141,6 +141,14 @@ won't change the current mask settings. It is more intended as an
internal API for use by the platform than an external API for use by
driver writers.

int
dma_set_mask_and_coherent(struct device *dev, u64 mask)

Checks to see if the mask is possible and updates the device
streaming and coherent DMA mask parameters if it is.

Returns: 0 if successful and a negative error if not.

int
dma_set_mask(struct device *dev, u64 mask)

+14 −0
Original line number Diff line number Diff line
@@ -97,6 +97,20 @@ static inline int dma_set_coherent_mask(struct device *dev, u64 mask)
}
#endif

/*
 * Set both the DMA mask and the coherent DMA mask to the same thing.
 * Note that we don't check the return value from dma_set_coherent_mask()
 * as the DMA API guarantees that the coherent DMA mask can be set to
 * the same or smaller than the streaming DMA mask.
 */
static inline int dma_set_mask_and_coherent(struct device *dev, u64 mask)
{
	int rc = dma_set_mask(dev, mask);
	if (rc == 0)
		dma_set_coherent_mask(dev, mask);
	return rc;
}

extern u64 dma_get_required_mask(struct device *dev);

static inline unsigned int dma_get_max_seg_size(struct device *dev)