iommu.lists.linux-foundation.org archive mirror
 help / color / mirror / Atom feed
* two dma-direct fixes for 4.18
@ 2018-08-24  6:53 Christoph Hellwig
       [not found] ` <20180824065324.654-1-hch-jcswGhMUV9g@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2018-08-24  6:53 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo, robin.murphy-5wv7dgnIgG8

Ensure we properly take the phys_to_dma translations into account when
checking dma masks.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] kernel/dma/direct: take DMA offset into account in dma_direct_supported
       [not found] ` <20180824065324.654-1-hch-jcswGhMUV9g@public.gmane.org>
@ 2018-08-24  6:53   ` Christoph Hellwig
       [not found]     ` <20180824065324.654-2-hch-jcswGhMUV9g@public.gmane.org>
  2018-08-24  6:53   ` [PATCH 2/2] kernel/dma/direct: refine dma_direct_alloc zone selection Christoph Hellwig
  1 sibling, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2018-08-24  6:53 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo, robin.murphy-5wv7dgnIgG8

When a device has a DMA offset the dma capable result will change due
to the difference between the physical and DMA address.  Take that into
account.

Signed-off-by: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>
Reviewed-by: Benjamin Herrenschmidt <benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
---
 kernel/dma/direct.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index 1c35b7b945d0..de87b0282e74 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -168,7 +168,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
 int dma_direct_supported(struct device *dev, u64 mask)
 {
 #ifdef CONFIG_ZONE_DMA
-	if (mask < DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+	if (mask < phys_to_dma(dev, DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)))
 		return 0;
 #else
 	/*
@@ -177,7 +177,7 @@ int dma_direct_supported(struct device *dev, u64 mask)
 	 * memory, or by providing a ZONE_DMA32.  If neither is the case, the
 	 * architecture needs to use an IOMMU instead of the direct mapping.
 	 */
-	if (mask < DMA_BIT_MASK(32))
+	if (mask < phys_to_dma(dev, DMA_BIT_MASK(32)))
 		return 0;
 #endif
 	/*
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] kernel/dma/direct: refine dma_direct_alloc zone selection
       [not found] ` <20180824065324.654-1-hch-jcswGhMUV9g@public.gmane.org>
  2018-08-24  6:53   ` [PATCH 1/2] kernel/dma/direct: take DMA offset into account in dma_direct_supported Christoph Hellwig
@ 2018-08-24  6:53   ` Christoph Hellwig
       [not found]     ` <20180824065324.654-3-hch-jcswGhMUV9g@public.gmane.org>
  1 sibling, 1 reply; 7+ messages in thread
From: Christoph Hellwig @ 2018-08-24  6:53 UTC (permalink / raw)
  To: iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo, robin.murphy-5wv7dgnIgG8

We need to take the DMA offset and encryption bit into account when selecting
a zone.  Add a helper that takes those into account and use it.

Signed-off-by: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>
---
 kernel/dma/direct.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
index de87b0282e74..3f8b596ea393 100644
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -58,6 +58,14 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
 	return addr + size - 1 <= dev->coherent_dma_mask;
 }
 
+static bool dma_coherent_below(struct device *dev, u64 mask)
+{
+	dma_addr_t addr = force_dma_unencrypted() ?
+		__phys_to_dma(dev, mask) : phys_to_dma(dev, mask);
+
+	return dev->coherent_dma_mask <= addr;
+}
+
 void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 		gfp_t gfp, unsigned long attrs)
 {
@@ -70,9 +78,9 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 	gfp &= ~__GFP_ZERO;
 
 	/* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */
-	if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+	if (dma_coherent_below(dev, DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)))
 		gfp |= GFP_DMA;
-	if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
+	if (dma_coherent_below(dev, DMA_BIT_MASK(32) && !(gfp & GFP_DMA)))
 		gfp |= GFP_DMA32;
 
 again:
@@ -93,14 +101,14 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
 		page = NULL;
 
 		if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
-		    dev->coherent_dma_mask < DMA_BIT_MASK(64) &&
+		    dma_coherent_below(dev, DMA_BIT_MASK(64)) &&
 		    !(gfp & (GFP_DMA32 | GFP_DMA))) {
 			gfp |= GFP_DMA32;
 			goto again;
 		}
 
 		if (IS_ENABLED(CONFIG_ZONE_DMA) &&
-		    dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
+		    dma_coherent_below(dev, DMA_BIT_MASK(32)) &&
 		    !(gfp & GFP_DMA)) {
 			gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
 			goto again;
-- 
2.18.0

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] kernel/dma/direct: take DMA offset into account in dma_direct_supported
       [not found]     ` <20180824065324.654-2-hch-jcswGhMUV9g@public.gmane.org>
@ 2018-08-24 11:11       ` Robin Murphy
       [not found]         ` <0e95df80-38f7-7970-ef74-419567f13fdc-5wv7dgnIgG8@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Robin Murphy @ 2018-08-24 11:11 UTC (permalink / raw)
  To: Christoph Hellwig,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo

On 24/08/18 07:53, Christoph Hellwig wrote:
> When a device has a DMA offset the dma capable result will change due
> to the difference between the physical and DMA address.  Take that into
> account.

The "phys_to_dma(..., DMA_BIT_MASK(...))" idiom always looks like a 
glaring error at first glance, but this whole function is fairly 
unintuitive anyway, and ultimately I think the change does work out to 
be correct.

It might be nicer if we could reference max_zone_pfns[] for a bit more 
clarity, but I guess that's not arch-independent.

Reviewed-by: Robin Murphy <robin.murphy-5wv7dgnIgG8@public.gmane.org>

> Signed-off-by: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>
> Reviewed-by: Benjamin Herrenschmidt <benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
> ---
>   kernel/dma/direct.c | 4 ++--
>   1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index 1c35b7b945d0..de87b0282e74 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -168,7 +168,7 @@ int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl, int nents,
>   int dma_direct_supported(struct device *dev, u64 mask)
>   {
>   #ifdef CONFIG_ZONE_DMA
> -	if (mask < DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
> +	if (mask < phys_to_dma(dev, DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)))
>   		return 0;
>   #else
>   	/*
> @@ -177,7 +177,7 @@ int dma_direct_supported(struct device *dev, u64 mask)
>   	 * memory, or by providing a ZONE_DMA32.  If neither is the case, the
>   	 * architecture needs to use an IOMMU instead of the direct mapping.
>   	 */
> -	if (mask < DMA_BIT_MASK(32))
> +	if (mask < phys_to_dma(dev, DMA_BIT_MASK(32)))
>   		return 0;
>   #endif
>   	/*
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] kernel/dma/direct: refine dma_direct_alloc zone selection
       [not found]     ` <20180824065324.654-3-hch-jcswGhMUV9g@public.gmane.org>
@ 2018-08-24 11:38       ` Robin Murphy
       [not found]         ` <bfba5bae-a88c-f777-ba1f-f0db310904dc-5wv7dgnIgG8@public.gmane.org>
  0 siblings, 1 reply; 7+ messages in thread
From: Robin Murphy @ 2018-08-24 11:38 UTC (permalink / raw)
  To: Christoph Hellwig,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo

On 24/08/18 07:53, Christoph Hellwig wrote:
> We need to take the DMA offset and encryption bit into account when selecting
> a zone.  Add a helper that takes those into account and use it.
> 
> Signed-off-by: Christoph Hellwig <hch-jcswGhMUV9g@public.gmane.org>
> ---
>   kernel/dma/direct.c | 16 ++++++++++++----
>   1 file changed, 12 insertions(+), 4 deletions(-)
> 
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> index de87b0282e74..3f8b596ea393 100644
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -58,6 +58,14 @@ static bool dma_coherent_ok(struct device *dev, phys_addr_t phys, size_t size)
>   	return addr + size - 1 <= dev->coherent_dma_mask;
>   }
>   
> +static bool dma_coherent_below(struct device *dev, u64 mask)
> +{
> +	dma_addr_t addr = force_dma_unencrypted() ?
> +		__phys_to_dma(dev, mask) : phys_to_dma(dev, mask);
> +
> +	return dev->coherent_dma_mask <= addr;
> +}
> +
>   void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
>   		gfp_t gfp, unsigned long attrs)
>   {
> @@ -70,9 +78,9 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
>   	gfp &= ~__GFP_ZERO;
>   
>   	/* GFP_DMA32 and GFP_DMA are no ops without the corresponding zones: */
> -	if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
> +	if (dma_coherent_below(dev, DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)))
>   		gfp |= GFP_DMA;
> -	if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
> +	if (dma_coherent_below(dev, DMA_BIT_MASK(32) && !(gfp & GFP_DMA)))
>   		gfp |= GFP_DMA32;
>   
>   again:
> @@ -93,14 +101,14 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
>   		page = NULL;
>   
>   		if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
> -		    dev->coherent_dma_mask < DMA_BIT_MASK(64) &&

We're effectively changing the "<" into a "<="...

> +		    dma_coherent_below(dev, DMA_BIT_MASK(64)) &&

...which I think means this check now *always* returns true...

>   		    !(gfp & (GFP_DMA32 | GFP_DMA))) {
>   			gfp |= GFP_DMA32;
>   			goto again;
>   		}
>   
>   		if (IS_ENABLED(CONFIG_ZONE_DMA) &&
> -		    dev->coherent_dma_mask < DMA_BIT_MASK(32) &&
> +		    dma_coherent_below(dev, DMA_BIT_MASK(32)) &&

...and this one subtly changes WRT ZONE_DMA32, but I can't quite figure 
out how much that matters :/

Robin.

>   		    !(gfp & GFP_DMA)) {
>   			gfp = (gfp & ~GFP_DMA32) | GFP_DMA;
>   			goto again;
> 

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] kernel/dma/direct: refine dma_direct_alloc zone selection
       [not found]         ` <bfba5bae-a88c-f777-ba1f-f0db310904dc-5wv7dgnIgG8@public.gmane.org>
@ 2018-08-24 11:49           ` Robin Murphy
  0 siblings, 0 replies; 7+ messages in thread
From: Robin Murphy @ 2018-08-24 11:49 UTC (permalink / raw)
  To: Christoph Hellwig,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA
  Cc: thomas.lendacky-5C7GfCeVMHo

On 24/08/18 12:38, Robin Murphy wrote:
> On 24/08/18 07:53, Christoph Hellwig wrote:
>> We need to take the DMA offset and encryption bit into account when 
>> selecting
>> a zone.  Add a helper that takes those into account and use it.
>>
>> Signed-off-by: Christoph Hellwig <hch@lst.de>
>> ---
>>   kernel/dma/direct.c | 16 ++++++++++++----
>>   1 file changed, 12 insertions(+), 4 deletions(-)
>>
>> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
>> index de87b0282e74..3f8b596ea393 100644
>> --- a/kernel/dma/direct.c
>> +++ b/kernel/dma/direct.c
>> @@ -58,6 +58,14 @@ static bool dma_coherent_ok(struct device *dev, 
>> phys_addr_t phys, size_t size)
>>       return addr + size - 1 <= dev->coherent_dma_mask;
>>   }
>> +static bool dma_coherent_below(struct device *dev, u64 mask)
>> +{
>> +    dma_addr_t addr = force_dma_unencrypted() ?
>> +        __phys_to_dma(dev, mask) : phys_to_dma(dev, mask);
>> +
>> +    return dev->coherent_dma_mask <= addr;
>> +}
>> +
>>   void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t 
>> *dma_handle,
>>           gfp_t gfp, unsigned long attrs)
>>   {
>> @@ -70,9 +78,9 @@ void *dma_direct_alloc(struct device *dev, size_t 
>> size, dma_addr_t *dma_handle,
>>       gfp &= ~__GFP_ZERO;
>>       /* GFP_DMA32 and GFP_DMA are no ops without the corresponding 
>> zones: */
>> -    if (dev->coherent_dma_mask <= DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
>> +    if (dma_coherent_below(dev, DMA_BIT_MASK(ARCH_ZONE_DMA_BITS)))
>>           gfp |= GFP_DMA;
>> -    if (dev->coherent_dma_mask <= DMA_BIT_MASK(32) && !(gfp & GFP_DMA))
>> +    if (dma_coherent_below(dev, DMA_BIT_MASK(32) && !(gfp & GFP_DMA)))
>>           gfp |= GFP_DMA32;
>>   again:
>> @@ -93,14 +101,14 @@ void *dma_direct_alloc(struct device *dev, size_t 
>> size, dma_addr_t *dma_handle,
>>           page = NULL;
>>           if (IS_ENABLED(CONFIG_ZONE_DMA32) &&
>> -            dev->coherent_dma_mask < DMA_BIT_MASK(64) &&
> 
> We're effectively changing the "<" into a "<="...
> 
>> +            dma_coherent_below(dev, DMA_BIT_MASK(64)) &&
> 
> ...which I think means this check now *always* returns true...

Although on closer inspection that was effectively already the case - we 
could never get here if dev->coherent_dma_mask == DMA_BIT_MASK(64), 
because dma_coherent_ok() couldn't possibly have returned false in the 
first place. So this one was always unnecessary.

Robin.
_______________________________________________
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] kernel/dma/direct: take DMA offset into account in dma_direct_supported
       [not found]         ` <0e95df80-38f7-7970-ef74-419567f13fdc-5wv7dgnIgG8@public.gmane.org>
@ 2018-08-29 16:59           ` Christoph Hellwig
  0 siblings, 0 replies; 7+ messages in thread
From: Christoph Hellwig @ 2018-08-29 16:59 UTC (permalink / raw)
  To: Robin Murphy
  Cc: thomas.lendacky-5C7GfCeVMHo,
	iommu-cunTk1MwBs9QetFLy7KEm3xJsTq8ys+cHZ5vskTnxNA,
	Christoph Hellwig

On Fri, Aug 24, 2018 at 12:11:23PM +0100, Robin Murphy wrote:
> On 24/08/18 07:53, Christoph Hellwig wrote:
>> When a device has a DMA offset the dma capable result will change due
>> to the difference between the physical and DMA address.  Take that into
>> account.
>
> The "phys_to_dma(..., DMA_BIT_MASK(...))" idiom always looks like a glaring 
> error at first glance, but this whole function is fairly unintuitive 
> anyway, and ultimately I think the change does work out to be correct.
>
> It might be nicer if we could reference max_zone_pfns[] for a bit more 
> clarity, but I guess that's not arch-independent.

Not just arch specific, but also local variables.  There is
arch_zone_lowest_possible_pfn in page_alloc.c, but that gets discarded
after init.  That being said this is the right direction and I'll
look into it for 4.20 or later.

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2018-08-29 16:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2018-08-24  6:53 two dma-direct fixes for 4.18 Christoph Hellwig
     [not found] ` <20180824065324.654-1-hch-jcswGhMUV9g@public.gmane.org>
2018-08-24  6:53   ` [PATCH 1/2] kernel/dma/direct: take DMA offset into account in dma_direct_supported Christoph Hellwig
     [not found]     ` <20180824065324.654-2-hch-jcswGhMUV9g@public.gmane.org>
2018-08-24 11:11       ` Robin Murphy
     [not found]         ` <0e95df80-38f7-7970-ef74-419567f13fdc-5wv7dgnIgG8@public.gmane.org>
2018-08-29 16:59           ` Christoph Hellwig
2018-08-24  6:53   ` [PATCH 2/2] kernel/dma/direct: refine dma_direct_alloc zone selection Christoph Hellwig
     [not found]     ` <20180824065324.654-3-hch-jcswGhMUV9g@public.gmane.org>
2018-08-24 11:38       ` Robin Murphy
     [not found]         ` <bfba5bae-a88c-f777-ba1f-f0db310904dc-5wv7dgnIgG8@public.gmane.org>
2018-08-24 11:49           ` Robin Murphy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).