On Wed, May 02, 2018 at 02:07:23PM +1000, Alexey Kardashevskiy wrote:
> At the moment we only support in the host the IOMMU page sizes which
> the guest is aware of, which is 4KB/64KB/16MB. However P9 does not support
> 16MB IOMMU pages, 2MB and 1GB pages are supported instead. We can still
> emulate bigger guest pages (for example 16MB) with smaller host pages
> (4KB/64KB/2MB).
> 
> This allows the physical IOMMU pages to use a page size smaller or equal
> than the guest visible IOMMU page size.
> 
> Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru>

Reviewed-by: David Gibson <da...@gibson.dropbear.id.au>

Except for one possible nit..

> ---
>  arch/powerpc/kvm/book3s_64_vio.c    | 66 
> +++++++++++++++++++++++++++++--------
>  arch/powerpc/kvm/book3s_64_vio_hv.c | 52 +++++++++++++++++++++++++----
>  2 files changed, 98 insertions(+), 20 deletions(-)
> 
> diff --git a/arch/powerpc/kvm/book3s_64_vio.c 
> b/arch/powerpc/kvm/book3s_64_vio.c
> index 041e54d..e10d6a3 100644
> --- a/arch/powerpc/kvm/book3s_64_vio.c
> +++ b/arch/powerpc/kvm/book3s_64_vio.c
> @@ -176,14 +176,12 @@ extern long kvm_spapr_tce_attach_iommu_group(struct kvm 
> *kvm, int tablefd,
>  
>               if (!tbltmp)
>                       continue;
> -             /*
> -              * Make sure hardware table parameters are exactly the same;
> -              * this is used in the TCE handlers where boundary checks
> -              * use only the first attached table.
> -              */
> -             if ((tbltmp->it_page_shift == stt->page_shift) &&
> -                             (tbltmp->it_offset == stt->offset) &&
> -                             (tbltmp->it_size == stt->size)) {
> +             /* Make sure hardware table parameters are compatible */
> +             if ((tbltmp->it_page_shift <= stt->page_shift) &&
> +                             (tbltmp->it_offset << tbltmp->it_page_shift ==
> +                              stt->offset << stt->page_shift) &&
> +                             (tbltmp->it_size << tbltmp->it_page_shift ==
> +                              stt->size << stt->page_shift)) {

Do we need to worry about stt->offset << stt->page_shift overflowing
with a buggy or malicious userspace?

>                       /*
>                        * Reference the table to avoid races with
>                        * add/remove DMA windows.
> @@ -396,7 +394,7 @@ static long kvmppc_tce_iommu_mapped_dec(struct kvm *kvm,
>       return H_SUCCESS;
>  }
>  
> -static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
> +static long kvmppc_tce_iommu_do_unmap(struct kvm *kvm,
>               struct iommu_table *tbl, unsigned long entry)
>  {
>       enum dma_data_direction dir = DMA_NONE;
> @@ -416,7 +414,25 @@ static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
>       return ret;
>  }
>  
> -long kvmppc_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
> +static long kvmppc_tce_iommu_unmap(struct kvm *kvm,
> +             struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
> +             unsigned long entry)
> +{
> +     unsigned long ret = H_SUCCESS;
> +     unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
> +     unsigned long io_entry = entry * subpages;
> +     unsigned long subpg;
> +
> +     for (subpg = 0; subpg < subpages; ++subpg) {
> +             ret = kvmppc_tce_iommu_do_unmap(kvm, tbl, io_entry + subpg);
> +             if (ret != H_SUCCESS)
> +                     break;
> +     }
> +
> +     return ret;
> +}
> +
> +long kvmppc_tce_iommu_do_map(struct kvm *kvm, struct iommu_table *tbl,
>               unsigned long entry, unsigned long ua,
>               enum dma_data_direction dir)
>  {
> @@ -453,6 +469,28 @@ long kvmppc_tce_iommu_map(struct kvm *kvm, struct 
> iommu_table *tbl,
>       return 0;
>  }
>  
> +static long kvmppc_tce_iommu_map(struct kvm *kvm,
> +             struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
> +             unsigned long entry, unsigned long ua,
> +             enum dma_data_direction dir)
> +{
> +     unsigned long ret = H_SUCCESS;
> +     unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
> +     unsigned long io_entry = entry * subpages;
> +     unsigned long subpg, pgoff;
> +
> +     for (subpg = 0, pgoff = 0; subpg < subpages;
> +                     ++subpg, pgoff += IOMMU_PAGE_SIZE(tbl)) {
> +
> +             ret = kvmppc_tce_iommu_do_map(kvm, tbl,
> +                             io_entry + subpg, ua + pgoff, dir);
> +             if (ret != H_SUCCESS)
> +                     break;
> +     }
> +
> +     return ret;
> +}
> +
>  long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
>                     unsigned long ioba, unsigned long tce)
>  {
> @@ -491,10 +529,10 @@ long kvmppc_h_put_tce(struct kvm_vcpu *vcpu, unsigned 
> long liobn,
>  
>       list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
>               if (dir == DMA_NONE)
> -                     ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
> +                     ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
>                                       stit->tbl, entry);
>               else
> -                     ret = kvmppc_tce_iommu_map(vcpu->kvm, stit->tbl,
> +                     ret = kvmppc_tce_iommu_map(vcpu->kvm, stt, stit->tbl,
>                                       entry, ua, dir);
>  
>               if (ret == H_SUCCESS)
> @@ -570,7 +608,7 @@ long kvmppc_h_put_tce_indirect(struct kvm_vcpu *vcpu,
>                       return H_PARAMETER;
>  
>               list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
> -                     ret = kvmppc_tce_iommu_map(vcpu->kvm,
> +                     ret = kvmppc_tce_iommu_map(vcpu->kvm, stt,
>                                       stit->tbl, entry + i, ua,
>                                       iommu_tce_direction(tce));
>  
> @@ -618,7 +656,7 @@ long kvmppc_h_stuff_tce(struct kvm_vcpu *vcpu,
>               unsigned long entry = ioba >> stt->page_shift;
>  
>               for (i = 0; i < npages; ++i) {
> -                     ret = kvmppc_tce_iommu_unmap(vcpu->kvm,
> +                     ret = kvmppc_tce_iommu_unmap(vcpu->kvm, stt,
>                                       stit->tbl, entry + i);
>  
>                       if (ret == H_SUCCESS)
> diff --git a/arch/powerpc/kvm/book3s_64_vio_hv.c 
> b/arch/powerpc/kvm/book3s_64_vio_hv.c
> index e220fab..258e786 100644
> --- a/arch/powerpc/kvm/book3s_64_vio_hv.c
> +++ b/arch/powerpc/kvm/book3s_64_vio_hv.c
> @@ -221,7 +221,7 @@ static long kvmppc_rm_tce_iommu_mapped_dec(struct kvm 
> *kvm,
>       return H_SUCCESS;
>  }
>  
> -static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
> +static long kvmppc_rm_tce_iommu_do_unmap(struct kvm *kvm,
>               struct iommu_table *tbl, unsigned long entry)
>  {
>       enum dma_data_direction dir = DMA_NONE;
> @@ -245,7 +245,25 @@ static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
>       return ret;
>  }
>  
> -static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, struct iommu_table *tbl,
> +static long kvmppc_rm_tce_iommu_unmap(struct kvm *kvm,
> +             struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
> +             unsigned long entry)
> +{
> +     unsigned long ret = H_SUCCESS;
> +     unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
> +     unsigned long io_entry = entry * subpages;
> +     unsigned long subpg;
> +
> +     for (subpg = 0; subpg < subpages; ++subpg) {
> +             ret = kvmppc_rm_tce_iommu_do_unmap(kvm, tbl, io_entry + subpg);
> +             if (ret != H_SUCCESS)
> +                     break;
> +     }
> +
> +     return ret;
> +}
> +
> +static long kvmppc_rm_tce_iommu_do_map(struct kvm *kvm, struct iommu_table 
> *tbl,
>               unsigned long entry, unsigned long ua,
>               enum dma_data_direction dir)
>  {
> @@ -290,6 +308,28 @@ static long kvmppc_rm_tce_iommu_map(struct kvm *kvm, 
> struct iommu_table *tbl,
>       return 0;
>  }
>  
> +static long kvmppc_rm_tce_iommu_map(struct kvm *kvm,
> +             struct kvmppc_spapr_tce_table *stt, struct iommu_table *tbl,
> +             unsigned long entry, unsigned long ua,
> +             enum dma_data_direction dir)
> +{
> +     unsigned long ret = H_SUCCESS;
> +     unsigned long subpages = 1ULL << (stt->page_shift - tbl->it_page_shift);
> +     unsigned long io_entry = entry * subpages;
> +     unsigned long subpg, pgoff;
> +
> +     for (subpg = 0, pgoff = 0; subpg < subpages;
> +                     ++subpg, pgoff += IOMMU_PAGE_SIZE(tbl)) {
> +
> +             ret = kvmppc_rm_tce_iommu_do_map(kvm, tbl,
> +                             io_entry + subpg, ua + pgoff, dir);
> +             if (ret != H_SUCCESS)
> +                     break;
> +     }
> +
> +     return ret;
> +}
> +
>  long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, unsigned long liobn,
>               unsigned long ioba, unsigned long tce)
>  {
> @@ -327,10 +367,10 @@ long kvmppc_rm_h_put_tce(struct kvm_vcpu *vcpu, 
> unsigned long liobn,
>  
>       list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
>               if (dir == DMA_NONE)
> -                     ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm,
> +                     ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm, stt,
>                                       stit->tbl, entry);
>               else
> -                     ret = kvmppc_rm_tce_iommu_map(vcpu->kvm,
> +                     ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
>                                       stit->tbl, entry, ua, dir);
>  
>               if (ret == H_SUCCESS)
> @@ -477,7 +517,7 @@ long kvmppc_rm_h_put_tce_indirect(struct kvm_vcpu *vcpu,
>                       return H_PARAMETER;
>  
>               list_for_each_entry_lockless(stit, &stt->iommu_tables, next) {
> -                     ret = kvmppc_rm_tce_iommu_map(vcpu->kvm,
> +                     ret = kvmppc_rm_tce_iommu_map(vcpu->kvm, stt,
>                                       stit->tbl, entry + i, ua,
>                                       iommu_tce_direction(tce));
>  
> @@ -529,7 +569,7 @@ long kvmppc_rm_h_stuff_tce(struct kvm_vcpu *vcpu,
>               unsigned long entry = ioba >> stt->page_shift;
>  
>               for (i = 0; i < npages; ++i) {
> -                     ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm,
> +                     ret = kvmppc_rm_tce_iommu_unmap(vcpu->kvm, stt,
>                                       stit->tbl, entry + i);
>  
>                       if (ret == H_SUCCESS)

-- 
David Gibson                    | I'll have my music baroque, and my code
david AT gibson.dropbear.id.au  | minimalist, thank you.  NOT _the_ _other_
                                | _way_ _around_!
http://www.ozlabs.org/~dgibson

Attachment: signature.asc
Description: PGP signature

Reply via email to