On 19/12/2018 19:52, Alexey Kardashevskiy wrote:
> At the moment the powernv platform registers an IOMMU group for each PE.
> There is an exception though: an NVLink bridge which is attached to
> the corresponding GPU's IOMMU group making it a master.
> 
> Now we have POWER9 systems with GPUs connected to each other directly
> bypassing PCI. At the moment we do not control state of these links so
> we have to put such interconnected GPUs to one IOMMU group which
> means that the old scheme with one GPU as a master won't work - there will
> be up to 3 GPUs in such group.
> 
> This introduces a npu_comp struct which represents a compound IOMMU
> group made of multiple PEs - PCI PEs (for GPUs) and NPU PEs (for NVLink
> bridges). This converts the existing NVLink1 code to use the new scheme.
> From now on, each PE must have a valid iommu_table_group_ops which will
> either be called directly (for a single PE group) or indirectly from
> a compound group handlers.
> 
> This moves IOMMU group registration for NVLink-connected GPUs to npu-dma.c.
> For POWER8, this stores a new compound group pointer in the PE (so a GPU
> is still a master); for POWER9 the new group pointer is stored in an NPU
> (which is allocated per a PCI host controller).
> 
> Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru>
> ---
> Changes:
> v5:
> * now read page sizes from PHB NVLink to narrow down what the compoind PE
> can actually support (hint: 4K/64K only)
> ---
>  arch/powerpc/include/asm/pci.h            |   1 +
>  arch/powerpc/platforms/powernv/pci.h      |   7 +
>  arch/powerpc/platforms/powernv/npu-dma.c  | 291 ++++++++++++++++++++--
>  arch/powerpc/platforms/powernv/pci-ioda.c | 159 ++++--------
>  4 files changed, 322 insertions(+), 136 deletions(-)
> 
> diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h
> index baf2886..0c72f18 100644
> --- a/arch/powerpc/include/asm/pci.h
> +++ b/arch/powerpc/include/asm/pci.h
> @@ -132,5 +132,6 @@ extern struct pci_dev *pnv_pci_get_npu_dev(struct pci_dev 
> *gpdev, int index);
>  extern int pnv_npu2_init(struct pci_controller *hose);
>  extern int pnv_npu2_map_lpar_dev(struct pci_dev *gpdev, unsigned int lparid,
>               unsigned long msr);
> +extern int pnv_npu2_unmap_lpar_dev(struct pci_dev *gpdev);
>  
>  #endif /* __ASM_POWERPC_PCI_H */
> diff --git a/arch/powerpc/platforms/powernv/pci.h 
> b/arch/powerpc/platforms/powernv/pci.h
> index cf9f748..aef4bb5 100644
> --- a/arch/powerpc/platforms/powernv/pci.h
> +++ b/arch/powerpc/platforms/powernv/pci.h
> @@ -62,6 +62,7 @@ struct pnv_ioda_pe {
>  
>       /* "Base" iommu table, ie, 4K TCEs, 32-bit DMA */
>       struct iommu_table_group table_group;
> +     struct npu_comp         *npucomp;
>  
>       /* 64-bit TCE bypass region */
>       bool                    tce_bypass_enabled;
> @@ -201,6 +202,8 @@ extern void pnv_teardown_msi_irqs(struct pci_dev *pdev);
>  extern struct pnv_ioda_pe *pnv_ioda_get_pe(struct pci_dev *dev);
>  extern void pnv_set_msi_irq_chip(struct pnv_phb *phb, unsigned int virq);
>  extern void pnv_pci_ioda2_set_bypass(struct pnv_ioda_pe *pe, bool enable);
> +extern unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
> +             __u64 window_size, __u32 levels);
>  extern int pnv_eeh_post_init(void);
>  
>  extern void pe_level_printk(const struct pnv_ioda_pe *pe, const char *level,
> @@ -216,6 +219,10 @@ extern void pe_level_printk(const struct pnv_ioda_pe 
> *pe, const char *level,
>  extern void pnv_npu_try_dma_set_bypass(struct pci_dev *gpdev, bool bypass);
>  extern void pnv_pci_ioda2_tce_invalidate_entire(struct pnv_phb *phb, bool 
> rm);
>  extern struct pnv_ioda_pe *pnv_pci_npu_setup_iommu(struct pnv_ioda_pe *npe);
> +extern struct iommu_table_group *pnv_try_setup_npu_table_group(
> +             struct pnv_ioda_pe *pe);
> +extern struct iommu_table_group *pnv_npu_compound_attach(
> +             struct pnv_ioda_pe *pe);
>  
>  /* pci-ioda-tce.c */
>  #define POWERNV_IOMMU_DEFAULT_LEVELS 1
> diff --git a/arch/powerpc/platforms/powernv/npu-dma.c 
> b/arch/powerpc/platforms/powernv/npu-dma.c
> index dc629ee..3468eaa 100644
> --- a/arch/powerpc/platforms/powernv/npu-dma.c
> +++ b/arch/powerpc/platforms/powernv/npu-dma.c
> @@ -328,31 +328,6 @@ static struct iommu_table_group_ops pnv_pci_npu_ops = {
>       .unset_window = pnv_npu_unset_window,
>       .take_ownership = pnv_npu_take_ownership,
>  };
> -
> -struct pnv_ioda_pe *pnv_pci_npu_setup_iommu(struct pnv_ioda_pe *npe)
> -{
> -     struct pnv_phb *phb = npe->phb;
> -     struct pci_bus *pbus = phb->hose->bus;
> -     struct pci_dev *npdev, *gpdev = NULL, *gptmp;
> -     struct pnv_ioda_pe *gpe = get_gpu_pci_dev_and_pe(npe, &gpdev);
> -
> -     if (!gpe || !gpdev)
> -             return NULL;
> -
> -     npe->table_group.ops = &pnv_pci_npu_ops;
> -
> -     list_for_each_entry(npdev, &pbus->devices, bus_list) {
> -             gptmp = pnv_pci_get_gpu_dev(npdev);
> -
> -             if (gptmp != gpdev)
> -                     continue;
> -
> -             pe_info(gpe, "Attached NPU %s\n", dev_name(&npdev->dev));
> -             iommu_group_add_device(gpe->table_group.group, &npdev->dev);
> -     }
> -
> -     return gpe;
> -}
>  #endif /* !CONFIG_IOMMU_API */
>  
>  /*
> @@ -360,6 +335,17 @@ struct pnv_ioda_pe *pnv_pci_npu_setup_iommu(struct 
> pnv_ioda_pe *npe)
>   */
>  /* Maximum possible number of ATSD MMIO registers per NPU */
>  #define NV_NMMU_ATSD_REGS 8
> +#define NV_NPU_MAX_PE_NUM    16
> +
> +/*
> + * A compound NPU IOMMU group which might consist of 1 GPU + 2xNPUs (POWER8) 
> or
> + * up to 3 x (GPU + 2xNPUs) (POWER9).
> + */
> +struct npu_comp {
> +     struct iommu_table_group table_group;
> +     int pe_num;
> +     struct pnv_ioda_pe *pe[NV_NPU_MAX_PE_NUM];
> +};
>  
>  /* An NPU descriptor, valid for POWER9 only */
>  struct npu {
> @@ -372,8 +358,263 @@ struct npu {
>  
>       /* Do we need to explicitly flush the nest mmu? */
>       bool nmmu_flush;
> +
> +     struct npu_comp npucomp;
>  };
>  
> +#ifdef CONFIG_IOMMU_API
> +static long pnv_npu_peers_create_table_userspace(
> +             struct iommu_table_group *table_group,
> +             int num, __u32 page_shift, __u64 window_size, __u32 levels,
> +             struct iommu_table **ptbl)
> +{
> +     struct npu_comp *npucomp = container_of(table_group, struct npu_comp,
> +                     table_group);
> +
> +     if (!npucomp->pe_num || !npucomp->pe[0] ||
> +                     !npucomp->pe[0]->table_group.ops ||
> +                     !npucomp->pe[0]->table_group.ops->create_table)
> +             return -EFAULT;
> +
> +     return npucomp->pe[0]->table_group.ops->create_table(
> +                     &npucomp->pe[0]->table_group, num, page_shift,
> +                     window_size, levels, ptbl);
> +}
> +
> +static long pnv_npu_peers_set_window(struct iommu_table_group *table_group,
> +             int num, struct iommu_table *tbl)
> +{
> +     int i, j;
> +     long ret = 0;
> +     struct npu_comp *npucomp = container_of(table_group, struct npu_comp,
> +                     table_group);
> +
> +     for (i = 0; i < npucomp->pe_num; ++i) {
> +             struct pnv_ioda_pe *pe = npucomp->pe[i];
> +
> +             if (!pe->table_group.ops->set_window)
> +                     continue;
> +
> +             ret = pe->table_group.ops->set_window(&pe->table_group,
> +                             num, tbl);
> +             if (ret)
> +                     break;
> +     }
> +
> +     if (ret) {
> +             for (j = 0; j < i; ++j) {
> +                     struct pnv_ioda_pe *pe = npucomp->pe[j];
> +
> +                     if (!pe->table_group.ops->unset_window)
> +                             continue;
> +
> +                     ret = pe->table_group.ops->unset_window(
> +                                     &pe->table_group, num);
> +                     if (ret)
> +                             break;
> +             }
> +     } else {
> +             table_group->tables[num] = iommu_tce_table_get(tbl);
> +     }
> +
> +     return ret;
> +}
> +
> +static long pnv_npu_peers_unset_window(struct iommu_table_group *table_group,
> +             int num)
> +{
> +     int i, j;
> +     long ret = 0;
> +     struct npu_comp *npucomp = container_of(table_group, struct npu_comp,
> +                     table_group);
> +
> +     for (i = 0; i < npucomp->pe_num; ++i) {
> +             struct pnv_ioda_pe *pe = npucomp->pe[i];
> +
> +             WARN_ON(npucomp->table_group.tables[num] !=
> +                             table_group->tables[num]);
> +             if (!npucomp->table_group.tables[num])
> +                     continue;
> +
> +             if (!pe->table_group.ops->unset_window)
> +                     continue;
> +
> +             ret = pe->table_group.ops->unset_window(&pe->table_group, num);
> +             if (ret)
> +                     break;
> +     }
> +
> +     if (ret) {
> +             for (j = 0; j < i; ++j) {
> +                     struct pnv_ioda_pe *pe = npucomp->pe[j];
> +
> +                     if (!npucomp->table_group.tables[num])
> +                             continue;
> +
> +                     if (!pe->table_group.ops->set_window)
> +                             continue;
> +
> +                     ret = pe->table_group.ops->set_window(&pe->table_group,
> +                                     num, table_group->tables[num]);
> +                     if (ret)
> +                             break;
> +             }
> +     } else if (table_group->tables[num]) {
> +             iommu_tce_table_put(table_group->tables[num]);
> +             table_group->tables[num] = NULL;
> +     }
> +
> +     return ret;
> +}
> +
> +static void pnv_npu_peers_take_ownership(struct iommu_table_group 
> *table_group)
> +{
> +     int i;
> +     struct npu_comp *npucomp = container_of(table_group, struct npu_comp,
> +                     table_group);
> +
> +     for (i = 0; i < npucomp->pe_num; ++i) {
> +             struct pnv_ioda_pe *pe = npucomp->pe[i];
> +
> +             if (!pe->table_group.ops->take_ownership)
> +                     continue;
> +             pe->table_group.ops->take_ownership(&pe->table_group);
> +     }
> +}
> +
> +static void pnv_npu_peers_release_ownership(
> +             struct iommu_table_group *table_group)
> +{
> +     int i;
> +     struct npu_comp *npucomp = container_of(table_group, struct npu_comp,
> +                     table_group);
> +
> +     for (i = 0; i < npucomp->pe_num; ++i) {
> +             struct pnv_ioda_pe *pe = npucomp->pe[i];
> +
> +             if (!pe->table_group.ops->release_ownership)
> +                     continue;
> +             pe->table_group.ops->release_ownership(&pe->table_group);
> +     }
> +}
> +
> +static struct iommu_table_group_ops pnv_npu_peers_ops = {
> +     .get_table_size = pnv_pci_ioda2_get_table_size,
> +     .create_table = pnv_npu_peers_create_table_userspace,
> +     .set_window = pnv_npu_peers_set_window,
> +     .unset_window = pnv_npu_peers_unset_window,
> +     .take_ownership = pnv_npu_peers_take_ownership,
> +     .release_ownership = pnv_npu_peers_release_ownership,
> +};
> +
> +static void pnv_comp_attach_table_group(struct npu_comp *npucomp,
> +             struct pnv_ioda_pe *pe)
> +{
> +     if (WARN_ON(npucomp->pe_num == NV_NPU_MAX_PE_NUM))
> +             return;
> +
> +     npucomp->pe[npucomp->pe_num] = pe;
> +     ++npucomp->pe_num;
> +}
> +
> +struct iommu_table_group *pnv_try_setup_npu_table_group(struct pnv_ioda_pe 
> *pe)
> +{
> +     struct iommu_table_group *table_group;
> +     struct npu_comp *npucomp;
> +     struct pci_dev *gpdev = NULL;
> +     struct pci_controller *hose;
> +     struct pci_dev *npdev;


And of course I missed this one, again, should have been npdev=NULL
above :-/




> +
> +     list_for_each_entry(gpdev, &pe->pbus->devices, bus_list) {
> +             npdev = pnv_pci_get_npu_dev(gpdev, 0);
> +             if (npdev)
> +                     break;
> +     }
> +
> +     if (!npdev)
> +             /* It is not an NPU attached device, skip */
> +             return NULL;
> +
> +     hose = pci_bus_to_host(npdev->bus);
> +
> +     if (hose->npu) {
> +             table_group = &hose->npu->npucomp.table_group;
> +
> +             if (!table_group->group) {
> +                     table_group->ops = &pnv_npu_peers_ops;
> +                     iommu_register_group(table_group,
> +                                     hose->global_number,
> +                                     pe->pe_number);
> +             }
> +     } else {
> +             /* Create a group for 1 GPU and attached NPUs for POWER8 */
> +             pe->npucomp = kzalloc(sizeof(pe->npucomp), GFP_KERNEL);
> +             table_group = &pe->npucomp->table_group;
> +             table_group->ops = &pnv_npu_peers_ops;
> +             iommu_register_group(table_group, hose->global_number,
> +                             pe->pe_number);
> +     }
> +
> +     /* Steal capabilities from a GPU PE */
> +     table_group->max_dynamic_windows_supported =
> +             pe->table_group.max_dynamic_windows_supported;
> +     table_group->tce32_start = pe->table_group.tce32_start;
> +     table_group->tce32_size = pe->table_group.tce32_size;
> +     table_group->max_levels = pe->table_group.max_levels;
> +     if (!table_group->pgsizes)
> +             table_group->pgsizes = pe->table_group.pgsizes;
> +
> +     npucomp = container_of(table_group, struct npu_comp, table_group);
> +     pnv_comp_attach_table_group(npucomp, pe);
> +
> +     return table_group;
> +}
> +
> +struct iommu_table_group *pnv_npu_compound_attach(struct pnv_ioda_pe *pe)
> +{
> +     struct iommu_table_group *table_group;
> +     struct npu_comp *npucomp;
> +     struct pci_dev *gpdev = NULL;
> +     struct pci_dev *npdev;
> +     struct pnv_ioda_pe *gpe = get_gpu_pci_dev_and_pe(pe, &gpdev);
> +
> +     WARN_ON(!(pe->flags & PNV_IODA_PE_DEV));
> +     if (!gpe)
> +             return NULL;
> +
> +     /*
> +      * IODA2 bridges get this set up from pci_controller_ops::setup_bridge
> +      * but NPU bridges do not have this hook defined so we do it here.
> +      * We do not setup other table group parameters as they won't be used
> +      * anyway - NVLink bridges are subordinate PEs.
> +      */
> +     pe->table_group.ops = &pnv_pci_npu_ops;
> +
> +     table_group = iommu_group_get_iommudata(
> +                     iommu_group_get(&gpdev->dev));
> +
> +     /*
> +      * On P9 NPU PHB and PCI PHB support different page sizes,
> +      * keep only matching. We expect here that NVLink bridge PE pgsizes is
> +      * initialized by the caller.
> +      */
> +     table_group->pgsizes &= pe->table_group.pgsizes;
> +     npucomp = container_of(table_group, struct npu_comp, table_group);
> +     pnv_comp_attach_table_group(npucomp, pe);
> +
> +     list_for_each_entry(npdev, &pe->phb->hose->bus->devices, bus_list) {
> +             struct pci_dev *gpdevtmp = pnv_pci_get_gpu_dev(npdev);
> +
> +             if (gpdevtmp != gpdev)
> +                     continue;
> +
> +             iommu_add_device(table_group, &npdev->dev);
> +     }
> +
> +     return table_group;
> +}
> +#endif /* CONFIG_IOMMU_API */
> +
>  /* Maximum number of nvlinks per npu */
>  #define NV_MAX_LINKS 6
>  
> diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c 
> b/arch/powerpc/platforms/powernv/pci-ioda.c
> index 6972054..6fe8907 100644
> --- a/arch/powerpc/platforms/powernv/pci-ioda.c
> +++ b/arch/powerpc/platforms/powernv/pci-ioda.c
> @@ -190,7 +190,8 @@ static void pnv_ioda_free_pe(struct pnv_ioda_pe *pe)
>       unsigned int pe_num = pe->pe_number;
>  
>       WARN_ON(pe->pdev);
> -
> +     WARN_ON(pe->npucomp); /* NPUs are not supposed to be freed */
> +     kfree(pe->npucomp);
>       memset(pe, 0, sizeof(struct pnv_ioda_pe));
>       clear_bit(pe_num, phb->ioda.pe_alloc);
>  }
> @@ -1539,7 +1540,9 @@ void pnv_pci_sriov_disable(struct pci_dev *pdev)
>  static void pnv_pci_ioda2_setup_dma_pe(struct pnv_phb *phb,
>                                      struct pnv_ioda_pe *pe);
>  #ifdef CONFIG_IOMMU_API
> -static void pnv_ioda_setup_bus_iommu_group(struct pnv_ioda_pe *pe);
> +static void pnv_ioda_setup_bus_iommu_group(struct pnv_ioda_pe *pe,
> +             struct iommu_table_group *table_group, struct pci_bus *bus);
> +
>  #endif
>  static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, u16 num_vfs)
>  {
> @@ -1595,7 +1598,7 @@ static void pnv_ioda_setup_vf_PE(struct pci_dev *pdev, 
> u16 num_vfs)
>  
>               pnv_pci_ioda2_setup_dma_pe(phb, pe);
>  #ifdef CONFIG_IOMMU_API
> -             pnv_ioda_setup_bus_iommu_group(pe);
> +             pnv_ioda_setup_bus_iommu_group(pe, &pe->table_group, NULL);
>  #endif
>       }
>  }
> @@ -2557,7 +2560,7 @@ static long pnv_pci_ioda2_unset_window(struct 
> iommu_table_group *table_group,
>  #endif
>  
>  #ifdef CONFIG_IOMMU_API
> -static unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
> +unsigned long pnv_pci_ioda2_get_table_size(__u32 page_shift,
>               __u64 window_size, __u32 levels)
>  {
>       unsigned long bytes = 0;
> @@ -2631,127 +2634,40 @@ static struct iommu_table_group_ops 
> pnv_pci_ioda2_ops = {
>       .release_ownership = pnv_ioda2_release_ownership,
>  };
>  
> -static int gpe_table_group_to_npe_cb(struct device *dev, void *opaque)
> -{
> -     struct pci_controller *hose;
> -     struct pnv_phb *phb;
> -     struct pnv_ioda_pe **ptmppe = opaque;
> -     struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
> -     struct pci_dn *pdn = pci_get_pdn(pdev);
> -
> -     if (!pdn || pdn->pe_number == IODA_INVALID_PE)
> -             return 0;
> -
> -     hose = pci_bus_to_host(pdev->bus);
> -     phb = hose->private_data;
> -     if (phb->type != PNV_PHB_NPU_NVLINK)
> -             return 0;
> -
> -     *ptmppe = &phb->ioda.pe_array[pdn->pe_number];
> -
> -     return 1;
> -}
> -
> -/*
> - * This returns PE of associated NPU.
> - * This assumes that NPU is in the same IOMMU group with GPU and there is
> - * no other PEs.
> - */
> -static struct pnv_ioda_pe *gpe_table_group_to_npe(
> -             struct iommu_table_group *table_group)
> -{
> -     struct pnv_ioda_pe *npe = NULL;
> -     int ret = iommu_group_for_each_dev(table_group->group, &npe,
> -                     gpe_table_group_to_npe_cb);
> -
> -     BUG_ON(!ret || !npe);
> -
> -     return npe;
> -}
> -
> -static long pnv_pci_ioda2_npu_set_window(struct iommu_table_group 
> *table_group,
> -             int num, struct iommu_table *tbl)
> -{
> -     struct pnv_ioda_pe *npe = gpe_table_group_to_npe(table_group);
> -     long ret = pnv_pci_ioda2_set_window(table_group, num, tbl);
> -
> -     if (ret)
> -             return ret;
> -
> -     ret = npe->table_group.ops->set_window(&npe->table_group, num, tbl);
> -     if (ret)
> -             pnv_pci_ioda2_unset_window(table_group, num);
> -
> -     return ret;
> -}
> -
> -static long pnv_pci_ioda2_npu_unset_window(
> -             struct iommu_table_group *table_group,
> -             int num)
> -{
> -     struct pnv_ioda_pe *npe = gpe_table_group_to_npe(table_group);
> -     long ret = pnv_pci_ioda2_unset_window(table_group, num);
> -
> -     if (ret)
> -             return ret;
> -
> -     return npe->table_group.ops->unset_window(&npe->table_group, num);
> -}
> -
> -static void pnv_ioda2_npu_take_ownership(struct iommu_table_group 
> *table_group)
> -{
> -     struct pnv_ioda_pe *npe = gpe_table_group_to_npe(table_group);
> -
> -     npe->table_group.ops->take_ownership(&npe->table_group);
> -     pnv_ioda2_take_ownership(table_group);
> -}
> -
> -static struct iommu_table_group_ops pnv_pci_ioda2_npu_ops = {
> -     .get_table_size = pnv_pci_ioda2_get_table_size,
> -     .create_table = pnv_pci_ioda2_create_table_userspace,
> -     .set_window = pnv_pci_ioda2_npu_set_window,
> -     .unset_window = pnv_pci_ioda2_npu_unset_window,
> -     .take_ownership = pnv_ioda2_npu_take_ownership,
> -     .release_ownership = pnv_ioda2_release_ownership,
> -};
> -
>  static void pnv_ioda_setup_bus_iommu_group_add_devices(struct pnv_ioda_pe 
> *pe,
> +             struct iommu_table_group *table_group,
>               struct pci_bus *bus)
>  {
>       struct pci_dev *dev;
>  
>       list_for_each_entry(dev, &bus->devices, bus_list) {
> -             iommu_add_device(&pe->table_group, &dev->dev);
> +             iommu_add_device(table_group, &dev->dev);
>  
>               if ((pe->flags & PNV_IODA_PE_BUS_ALL) && dev->subordinate)
>                       pnv_ioda_setup_bus_iommu_group_add_devices(pe,
> -                                     dev->subordinate);
> +                                     table_group, dev->subordinate);
>       }
>  }
>  
> -static void pnv_ioda_setup_bus_iommu_group(struct pnv_ioda_pe *pe)
> +static void pnv_ioda_setup_bus_iommu_group(struct pnv_ioda_pe *pe,
> +             struct iommu_table_group *table_group, struct pci_bus *bus)
>  {
> -     if (!pnv_pci_ioda_pe_dma_weight(pe))
> -             return;
>  
> -     iommu_register_group(&pe->table_group, pe->phb->hose->global_number,
> -                     pe->pe_number);
> -
> -     /*
> -      * set_iommu_table_base(&pe->pdev->dev, tbl) should have been called
> -      * by now
> -      */
>       if (pe->flags & PNV_IODA_PE_DEV)
> -             iommu_add_device(&pe->table_group, &pe->pdev->dev);
> -     else if (pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL))
> -             pnv_ioda_setup_bus_iommu_group_add_devices(pe, pe->pbus);
> +             iommu_add_device(table_group, &pe->pdev->dev);
> +
> +     if ((pe->flags & (PNV_IODA_PE_BUS | PNV_IODA_PE_BUS_ALL)) || bus)
> +             pnv_ioda_setup_bus_iommu_group_add_devices(pe, table_group,
> +                             bus);
>  }
>  
> +static unsigned long pnv_ioda_parse_tce_sizes(struct pnv_phb *phb);
> +
>  static void pnv_pci_ioda_setup_iommu_api(void)
>  {
> -     struct pci_controller *hose, *tmp;
> +     struct pci_controller *hose;
>       struct pnv_phb *phb;
> -     struct pnv_ioda_pe *pe, *gpe;
> +     struct pnv_ioda_pe *pe;
>  
>       /*
>        * There are 4 types of PEs:
> @@ -2773,24 +2689,45 @@ static void pnv_pci_ioda_setup_iommu_api(void)
>               if (phb->type == PNV_PHB_NPU_NVLINK)
>                       continue;
>  
> -             list_for_each_entry(pe, &phb->ioda.pe_list, list)
> -                     pnv_ioda_setup_bus_iommu_group(pe);
> +             list_for_each_entry(pe, &phb->ioda.pe_list, list) {
> +                     struct iommu_table_group *table_group;
> +
> +                     table_group = pnv_try_setup_npu_table_group(pe);
> +                     if (!table_group) {
> +                             if (!pnv_pci_ioda_pe_dma_weight(pe))
> +                                     continue;
> +
> +                             table_group = &pe->table_group;
> +                             iommu_register_group(&pe->table_group,
> +                                             pe->phb->hose->global_number,
> +                                             pe->pe_number);
> +                     }
> +                     pnv_ioda_setup_bus_iommu_group(pe, table_group,
> +                                     pe->pbus);
> +             }
>       }
>  
>       /*
>        * Now we have all PHBs discovered, time to add NPU devices to
>        * the corresponding IOMMU groups.
>        */
> -     list_for_each_entry_safe(hose, tmp, &hose_list, list_node) {
> +     list_for_each_entry(hose, &hose_list, list_node) {
> +             unsigned long  pgsizes;
> +
>               phb = hose->private_data;
>  
>               if (phb->type != PNV_PHB_NPU_NVLINK)
>                       continue;
>  
> +             pgsizes = pnv_ioda_parse_tce_sizes(phb);
>               list_for_each_entry(pe, &phb->ioda.pe_list, list) {
> -                     gpe = pnv_pci_npu_setup_iommu(pe);
> -                     if (gpe)
> -                             gpe->table_group.ops = &pnv_pci_ioda2_npu_ops;
> +                     /*
> +                      * IODA2 bridges get this set up from
> +                      * pci_controller_ops::setup_bridge but NPU bridges
> +                      * do not have this hook defined so we do it here.
> +                      */
> +                     pe->table_group.pgsizes = pgsizes;
> +                     pnv_npu_compound_attach(pe);
>               }
>       }
>  }
> 

-- 
Alexey

Reply via email to