Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-02-28 Thread David Rientjes via iommu
On Fri, 17 Jan 2020, Tom Lendacky wrote:

> On 12/31/19 7:54 PM, David Rientjes wrote:
> > Christoph, Thomas, is something like this (without the diagnosic 
> > information included in this patch) acceptable for these allocations?  
> > Adding expansion support when the pool is half depleted wouldn't be *that* 
> > hard.
> 
> Sorry for the delay in responding...  Overall, I think this will work
> well. If you want the default size to be adjustable, you can always go
> with a Kconfig setting or a command line parameter or both (I realize the
> command line parameter is not optimal).
> 

Ok, so we've determined that we don't only have a dependency on GFP_DMA 
memory through the DMA API in a non-blocking context that needs to be 
unencrypted, but also GFP_KERNEL.  We don't have a dependency on GFP_DMA32 
memory (yet) but should likely provision for it.

So my patch would change by actually providing three separate pools, one 
for ZONE_DMA, one for ZONE_DMA32, and one for ZONE_NORMAL.  The ZONE_DMA 
already exists in the form of the atomic_pool, so it would add two 
additional pools that likely start out at the same size and dynamically 
expand with a kworker when its usage approaches the limitatios of the 
pool.  I don't necessarily like needing three separate pools, but I can't 
think of a better way to provide unencrypted memory for non-blocking 
allocations that work for all possible device gfp masks.

My idea right now is to create all three pools instead of the single 
atomic_pool, all 256KB in size, and anytime their usage reaches half their 
limit, we kick off some background work to double the size of the pool 
with GFP_KERNEL | __GFP_NORETRY.  Our experimentation suggests that a 
kworker would actually respond in time for this.

Any objections to this approach?  If so, an alternative suggestion would 
be appreciated :)  I plan on all atomic pools to be unencrypted at the 
time the allocation is successful unless there is some strange need for 
non-blocking atomic allocations through the DMA API that should *not* be 
encrypted.

> Just a couple of overall comments about the use of variable names and
> messages using both unencrypted and encrypted, I think the use should be
> consistent throughout the patch.
> 
> Thanks,
> Tom
> 
> > 
> > Or are there alternatives we should consider?  Thanks!
> > 
> > 
> > 
> > 
> > When AMD SEV is enabled in the guest, all allocations through 
> > dma_pool_alloc_page() must call set_memory_decrypted() for unencrypted 
> > DMA.  This includes dma_pool_alloc() and dma_direct_alloc_pages().  These 
> > calls may block which is not allowed in atomic allocation contexts such as 
> > from the NVMe driver.
> > 
> > Preallocate a complementary unecrypted DMA atomic pool that is initially 
> > 4MB in size.  This patch does not contain dynamic expansion, but that 
> > could be added if necessary.
> > 
> > In our stress testing, our peak unecrypted DMA atomic allocation 
> > requirements is ~1.4MB, so 4MB is plenty.  This pool is similar to the 
> > existing DMA atomic pool but is unencrypted.
> > 
> > Signed-off-by: David Rientjes 
> > ---
> >  Based on v5.4 HEAD.
> > 
> >  This commit contains diagnostic information and is not intended for use 
> >  in a production environment.
> > 
> >  arch/x86/Kconfig|   1 +
> >  drivers/iommu/dma-iommu.c   |   5 +-
> >  include/linux/dma-mapping.h |   7 ++-
> >  kernel/dma/direct.c |  16 -
> >  kernel/dma/remap.c  | 116 ++--
> >  5 files changed, 108 insertions(+), 37 deletions(-)
> > 
> > diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> > --- a/arch/x86/Kconfig
> > +++ b/arch/x86/Kconfig
> > @@ -1530,6 +1530,7 @@ config X86_CPA_STATISTICS
> >  config AMD_MEM_ENCRYPT
> > bool "AMD Secure Memory Encryption (SME) support"
> > depends on X86_64 && CPU_SUP_AMD
> > +   select DMA_DIRECT_REMAP
> > select DYNAMIC_PHYSICAL_MASK
> > select ARCH_USE_MEMREMAP_PROT
> > select ARCH_HAS_FORCE_DMA_UNENCRYPTED
> > diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> > --- a/drivers/iommu/dma-iommu.c
> > +++ b/drivers/iommu/dma-iommu.c
> > @@ -928,7 +928,7 @@ static void __iommu_dma_free(struct device *dev, size_t 
> > size, void *cpu_addr)
> >  
> > /* Non-coherent atomic allocation? Easy */
> > if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
> > -   dma_free_from_pool(cpu_addr, alloc_size))
> > +   dma_free_from_pool(dev, cpu_addr, alloc_size))
> > return;
> >  
> > if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
> > @@ -1011,7 +1011,8 @@ static void *iommu_dma_alloc(struct device *dev, 
> > size_t size,
> >  
> > if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
> > !gfpflags_allow_blocking(gfp) && !coherent)
> > -   cpu_addr = dma_alloc_from_pool(PAGE_ALIGN(size), , gfp);
> > +   cpu_addr = dma_alloc_from_pool(dev, PAGE_ALIGN(size), ,
> > +  gfp);

Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-17 Thread Tom Lendacky
On 12/31/19 7:54 PM, David Rientjes wrote:
> Christoph, Thomas, is something like this (without the diagnosic 
> information included in this patch) acceptable for these allocations?  
> Adding expansion support when the pool is half depleted wouldn't be *that* 
> hard.

Sorry for the delay in responding...  Overall, I think this will work
well. If you want the default size to be adjustable, you can always go
with a Kconfig setting or a command line parameter or both (I realize the
command line parameter is not optimal).

Just a couple of overall comments about the use of variable names and
messages using both unencrypted and encrypted, I think the use should be
consistent throughout the patch.

Thanks,
Tom

> 
> Or are there alternatives we should consider?  Thanks!
> 
> 
> 
> 
> When AMD SEV is enabled in the guest, all allocations through 
> dma_pool_alloc_page() must call set_memory_decrypted() for unencrypted 
> DMA.  This includes dma_pool_alloc() and dma_direct_alloc_pages().  These 
> calls may block which is not allowed in atomic allocation contexts such as 
> from the NVMe driver.
> 
> Preallocate a complementary unecrypted DMA atomic pool that is initially 
> 4MB in size.  This patch does not contain dynamic expansion, but that 
> could be added if necessary.
> 
> In our stress testing, our peak unecrypted DMA atomic allocation 
> requirements is ~1.4MB, so 4MB is plenty.  This pool is similar to the 
> existing DMA atomic pool but is unencrypted.
> 
> Signed-off-by: David Rientjes 
> ---
>  Based on v5.4 HEAD.
> 
>  This commit contains diagnostic information and is not intended for use 
>  in a production environment.
> 
>  arch/x86/Kconfig|   1 +
>  drivers/iommu/dma-iommu.c   |   5 +-
>  include/linux/dma-mapping.h |   7 ++-
>  kernel/dma/direct.c |  16 -
>  kernel/dma/remap.c  | 116 ++--
>  5 files changed, 108 insertions(+), 37 deletions(-)
> 
> diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
> --- a/arch/x86/Kconfig
> +++ b/arch/x86/Kconfig
> @@ -1530,6 +1530,7 @@ config X86_CPA_STATISTICS
>  config AMD_MEM_ENCRYPT
>   bool "AMD Secure Memory Encryption (SME) support"
>   depends on X86_64 && CPU_SUP_AMD
> + select DMA_DIRECT_REMAP
>   select DYNAMIC_PHYSICAL_MASK
>   select ARCH_USE_MEMREMAP_PROT
>   select ARCH_HAS_FORCE_DMA_UNENCRYPTED
> diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
> --- a/drivers/iommu/dma-iommu.c
> +++ b/drivers/iommu/dma-iommu.c
> @@ -928,7 +928,7 @@ static void __iommu_dma_free(struct device *dev, size_t 
> size, void *cpu_addr)
>  
>   /* Non-coherent atomic allocation? Easy */
>   if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
> - dma_free_from_pool(cpu_addr, alloc_size))
> + dma_free_from_pool(dev, cpu_addr, alloc_size))
>   return;
>  
>   if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {
> @@ -1011,7 +1011,8 @@ static void *iommu_dma_alloc(struct device *dev, size_t 
> size,
>  
>   if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
>   !gfpflags_allow_blocking(gfp) && !coherent)
> - cpu_addr = dma_alloc_from_pool(PAGE_ALIGN(size), , gfp);
> + cpu_addr = dma_alloc_from_pool(dev, PAGE_ALIGN(size), ,
> +gfp);
>   else
>   cpu_addr = iommu_dma_alloc_pages(dev, size, , gfp, attrs);
>   if (!cpu_addr)
> diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
> --- a/include/linux/dma-mapping.h
> +++ b/include/linux/dma-mapping.h
> @@ -629,9 +629,10 @@ void *dma_common_pages_remap(struct page **pages, size_t 
> size,
>   pgprot_t prot, const void *caller);
>  void dma_common_free_remap(void *cpu_addr, size_t size);
>  
> -bool dma_in_atomic_pool(void *start, size_t size);
> -void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags);
> -bool dma_free_from_pool(void *start, size_t size);
> +bool dma_in_atomic_pool(struct device *dev, void *start, size_t size);
> +void *dma_alloc_from_pool(struct device *dev, size_t size,
> +   struct page **ret_page, gfp_t flags);
> +bool dma_free_from_pool(struct device *dev, void *start, size_t size);
>  
>  int
>  dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, void 
> *cpu_addr,
> diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
> --- a/kernel/dma/direct.c
> +++ b/kernel/dma/direct.c
> @@ -10,6 +10,7 @@
>  #include 
>  #include 
>  #include 
> +#include 
>  #include 
>  #include 
>  #include 
> @@ -131,6 +132,13 @@ void *dma_direct_alloc_pages(struct device *dev, size_t 
> size,
>   struct page *page;
>   void *ret;
>  
> + if (!gfpflags_allow_blocking(gfp) && force_dma_unencrypted(dev)) {
> + ret = dma_alloc_from_pool(dev, size, , gfp);
> + if (!ret)
> + return NULL;
> + goto done;
> + }
> +
>   page = 

Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-09 Thread David Rientjes via iommu
On Thu, 9 Jan 2020, Christoph Hellwig wrote:

> > I'll rely on Thomas to chime in if this doesn't make sense for the SEV 
> > usecase.
> > 
> > I think the sizing of the single atomic pool needs to be determined.  Our 
> > peak usage that we have measured from NVMe is ~1.4MB and atomic_pool is 
> > currently sized to 256KB by default.  I'm unsure at this time if we need 
> > to be able to dynamically expand this pool with a kworker.
> >
> > Maybe when CONFIG_AMD_MEM_ENCRYPT is enabled this atomic pool should be 
> > sized to 2MB or so and then when it reaches half capacity we schedule some 
> > background work to dynamically increase it?  That wouldn't be hard unless 
> > the pool can be rapidly depleted.
> > 
> 
> Note that a non-coherent architecture with the same workload would need
> the same size.
> 
> > Do we want to increase the atomic pool size by default and then do 
> > background dynamic expansion?
> 
> For now I'd just scale with system memory size.
> 

Thanks Christoph and Robin for the help, we're running some additional 
stress tests to double check that our required amount of memory from this 
pool is accurate.  Once that's done, I'll refresh the patch with th 
suggestions and propose it formally.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-09 Thread Christoph Hellwig
On Tue, Jan 07, 2020 at 11:57:24AM -0800, David Rientjes wrote:
> I'll rely on Thomas to chime in if this doesn't make sense for the SEV 
> usecase.
> 
> I think the sizing of the single atomic pool needs to be determined.  Our 
> peak usage that we have measured from NVMe is ~1.4MB and atomic_pool is 
> currently sized to 256KB by default.  I'm unsure at this time if we need 
> to be able to dynamically expand this pool with a kworker.
>
> Maybe when CONFIG_AMD_MEM_ENCRYPT is enabled this atomic pool should be 
> sized to 2MB or so and then when it reaches half capacity we schedule some 
> background work to dynamically increase it?  That wouldn't be hard unless 
> the pool can be rapidly depleted.
> 

Note that a non-coherent architecture with the same workload would need
the same size.

> Do we want to increase the atomic pool size by default and then do 
> background dynamic expansion?

For now I'd just scale with system memory size.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-07 Thread David Rientjes via iommu
On Tue, 7 Jan 2020, Christoph Hellwig wrote:

> > On 01/01/2020 1:54 am, David Rientjes via iommu wrote:
> >> Christoph, Thomas, is something like this (without the diagnosic
> >> information included in this patch) acceptable for these allocations?
> >> Adding expansion support when the pool is half depleted wouldn't be *that*
> >> hard.
> >>
> >> Or are there alternatives we should consider?  Thanks!
> >
> > Are there any platforms which require both non-cacheable remapping *and* 
> > unencrypted remapping for distinct subsets of devices?
> >
> > If not (and I'm assuming there aren't, because otherwise this patch is 
> > incomplete in covering only 2 of the 3 possible combinations), then 
> > couldn't we keep things simpler by just attributing both properties to the 
> > single "atomic pool" on the basis that one or the other will always be a 
> > no-op? In other words, basically just tweaking the existing "!coherent" 
> > tests to "!coherent || force_dma_unencrypted()" and doing 
> > set_dma_unencrypted() unconditionally in atomic_pool_init().
> 
> I think that would make most sense.
> 

I'll rely on Thomas to chime in if this doesn't make sense for the SEV 
usecase.

I think the sizing of the single atomic pool needs to be determined.  Our 
peak usage that we have measured from NVMe is ~1.4MB and atomic_pool is 
currently sized to 256KB by default.  I'm unsure at this time if we need 
to be able to dynamically expand this pool with a kworker.

Maybe when CONFIG_AMD_MEM_ENCRYPT is enabled this atomic pool should be 
sized to 2MB or so and then when it reaches half capacity we schedule some 
background work to dynamically increase it?  That wouldn't be hard unless 
the pool can be rapidly depleted.

Do we want to increase the atomic pool size by default and then do 
background dynamic expansion?
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-07 Thread Christoph Hellwig
On Mon, Jan 06, 2020 at 05:34:00PM +, Robin Murphy wrote:
> On 01/01/2020 1:54 am, David Rientjes via iommu wrote:
>> Christoph, Thomas, is something like this (without the diagnosic
>> information included in this patch) acceptable for these allocations?
>> Adding expansion support when the pool is half depleted wouldn't be *that*
>> hard.
>>
>> Or are there alternatives we should consider?  Thanks!
>
> Are there any platforms which require both non-cacheable remapping *and* 
> unencrypted remapping for distinct subsets of devices?
>
> If not (and I'm assuming there aren't, because otherwise this patch is 
> incomplete in covering only 2 of the 3 possible combinations), then 
> couldn't we keep things simpler by just attributing both properties to the 
> single "atomic pool" on the basis that one or the other will always be a 
> no-op? In other words, basically just tweaking the existing "!coherent" 
> tests to "!coherent || force_dma_unencrypted()" and doing 
> set_dma_unencrypted() unconditionally in atomic_pool_init().

I think that would make most sense.
___
iommu mailing list
iommu@lists.linux-foundation.org
https://lists.linuxfoundation.org/mailman/listinfo/iommu


Re: [rfc] dma-mapping: preallocate unencrypted DMA atomic pool

2020-01-06 Thread Robin Murphy

On 01/01/2020 1:54 am, David Rientjes via iommu wrote:

Christoph, Thomas, is something like this (without the diagnosic
information included in this patch) acceptable for these allocations?
Adding expansion support when the pool is half depleted wouldn't be *that*
hard.

Or are there alternatives we should consider?  Thanks!


Are there any platforms which require both non-cacheable remapping *and* 
unencrypted remapping for distinct subsets of devices?


If not (and I'm assuming there aren't, because otherwise this patch is 
incomplete in covering only 2 of the 3 possible combinations), then 
couldn't we keep things simpler by just attributing both properties to 
the single "atomic pool" on the basis that one or the other will always 
be a no-op? In other words, basically just tweaking the existing 
"!coherent" tests to "!coherent || force_dma_unencrypted()" and doing 
set_dma_unencrypted() unconditionally in atomic_pool_init().


Robin.


When AMD SEV is enabled in the guest, all allocations through
dma_pool_alloc_page() must call set_memory_decrypted() for unencrypted
DMA.  This includes dma_pool_alloc() and dma_direct_alloc_pages().  These
calls may block which is not allowed in atomic allocation contexts such as
from the NVMe driver.

Preallocate a complementary unecrypted DMA atomic pool that is initially
4MB in size.  This patch does not contain dynamic expansion, but that
could be added if necessary.

In our stress testing, our peak unecrypted DMA atomic allocation
requirements is ~1.4MB, so 4MB is plenty.  This pool is similar to the
existing DMA atomic pool but is unencrypted.

Signed-off-by: David Rientjes 
---
  Based on v5.4 HEAD.

  This commit contains diagnostic information and is not intended for use
  in a production environment.

  arch/x86/Kconfig|   1 +
  drivers/iommu/dma-iommu.c   |   5 +-
  include/linux/dma-mapping.h |   7 ++-
  kernel/dma/direct.c |  16 -
  kernel/dma/remap.c  | 116 ++--
  5 files changed, 108 insertions(+), 37 deletions(-)

diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -1530,6 +1530,7 @@ config X86_CPA_STATISTICS
  config AMD_MEM_ENCRYPT
bool "AMD Secure Memory Encryption (SME) support"
depends on X86_64 && CPU_SUP_AMD
+   select DMA_DIRECT_REMAP
select DYNAMIC_PHYSICAL_MASK
select ARCH_USE_MEMREMAP_PROT
select ARCH_HAS_FORCE_DMA_UNENCRYPTED
diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -928,7 +928,7 @@ static void __iommu_dma_free(struct device *dev, size_t 
size, void *cpu_addr)
  
  	/* Non-coherent atomic allocation? Easy */

if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&
-   dma_free_from_pool(cpu_addr, alloc_size))
+   dma_free_from_pool(dev, cpu_addr, alloc_size))
return;
  
  	if (IS_ENABLED(CONFIG_DMA_REMAP) && is_vmalloc_addr(cpu_addr)) {

@@ -1011,7 +1011,8 @@ static void *iommu_dma_alloc(struct device *dev, size_t 
size,
  
  	if (IS_ENABLED(CONFIG_DMA_DIRECT_REMAP) &&

!gfpflags_allow_blocking(gfp) && !coherent)
-   cpu_addr = dma_alloc_from_pool(PAGE_ALIGN(size), , gfp);
+   cpu_addr = dma_alloc_from_pool(dev, PAGE_ALIGN(size), ,
+  gfp);
else
cpu_addr = iommu_dma_alloc_pages(dev, size, , gfp, attrs);
if (!cpu_addr)
diff --git a/include/linux/dma-mapping.h b/include/linux/dma-mapping.h
--- a/include/linux/dma-mapping.h
+++ b/include/linux/dma-mapping.h
@@ -629,9 +629,10 @@ void *dma_common_pages_remap(struct page **pages, size_t 
size,
pgprot_t prot, const void *caller);
  void dma_common_free_remap(void *cpu_addr, size_t size);
  
-bool dma_in_atomic_pool(void *start, size_t size);

-void *dma_alloc_from_pool(size_t size, struct page **ret_page, gfp_t flags);
-bool dma_free_from_pool(void *start, size_t size);
+bool dma_in_atomic_pool(struct device *dev, void *start, size_t size);
+void *dma_alloc_from_pool(struct device *dev, size_t size,
+ struct page **ret_page, gfp_t flags);
+bool dma_free_from_pool(struct device *dev, void *start, size_t size);
  
  int

  dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, void 
*cpu_addr,
diff --git a/kernel/dma/direct.c b/kernel/dma/direct.c
--- a/kernel/dma/direct.c
+++ b/kernel/dma/direct.c
@@ -10,6 +10,7 @@
  #include 
  #include 
  #include 
+#include 
  #include 
  #include 
  #include 
@@ -131,6 +132,13 @@ void *dma_direct_alloc_pages(struct device *dev, size_t 
size,
struct page *page;
void *ret;
  
+	if (!gfpflags_allow_blocking(gfp) && force_dma_unencrypted(dev)) {

+   ret = dma_alloc_from_pool(dev, size, , gfp);
+   if (!ret)
+   return NULL;
+   goto done;
+   }
+