On Tue, Feb 16, 2021 at 02:33:07PM +1100, Alexey Kardashevskiy wrote:
> Most platforms allocate IOMMU table structures (specifically it_map)
> at the boot time and when this fails - it is a valid reason for panic().
> 
> However the powernv platform allocates it_map after a device is returned
> to the host OS after being passed through and this happens long after
> the host OS booted. It is quite possible to trigger the it_map allocation
> panic() and kill the host even though it is not necessary - the host OS
> can still use the DMA bypass mode (requires a tiny fraction of it_map's
> memory) and even if that fails, the host OS is runnnable as it was without
> the device for which allocating it_map causes the panic.
> 
> Instead of immediately crashing in a powernv/ioda2 system, this prints
> an error and continues. All other platforms still call panic().
> 
> Signed-off-by: Alexey Kardashevskiy <a...@ozlabs.ru>

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

> ---
>  arch/powerpc/kernel/iommu.c               |  6 ++++--
>  arch/powerpc/platforms/cell/iommu.c       |  3 ++-
>  arch/powerpc/platforms/pasemi/iommu.c     |  4 +++-
>  arch/powerpc/platforms/powernv/pci-ioda.c | 15 ++++++++-------
>  arch/powerpc/platforms/pseries/iommu.c    | 10 +++++++---
>  arch/powerpc/sysdev/dart_iommu.c          |  3 ++-
>  6 files changed, 26 insertions(+), 15 deletions(-)
> 
> diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
> index 8eb6eb0afa97..c1a5c366a664 100644
> --- a/arch/powerpc/kernel/iommu.c
> +++ b/arch/powerpc/kernel/iommu.c
> @@ -728,8 +728,10 @@ struct iommu_table *iommu_init_table(struct iommu_table 
> *tbl, int nid,
>       sz = BITS_TO_LONGS(tbl->it_size) * sizeof(unsigned long);
>  
>       tbl->it_map = vzalloc_node(sz, nid);
> -     if (!tbl->it_map)
> -             panic("iommu_init_table: Can't allocate %ld bytes\n", sz);
> +     if (!tbl->it_map) {
> +             pr_err("%s: Can't allocate %ld bytes\n", __func__, sz);
> +             return NULL;
> +     }
>  
>       iommu_table_reserve_pages(tbl, res_start, res_end);
>  
> diff --git a/arch/powerpc/platforms/cell/iommu.c 
> b/arch/powerpc/platforms/cell/iommu.c
> index 2124831cf57c..fa08699aedeb 100644
> --- a/arch/powerpc/platforms/cell/iommu.c
> +++ b/arch/powerpc/platforms/cell/iommu.c
> @@ -486,7 +486,8 @@ cell_iommu_setup_window(struct cbe_iommu *iommu, struct 
> device_node *np,
>       window->table.it_size = size >> window->table.it_page_shift;
>       window->table.it_ops = &cell_iommu_ops;
>  
> -     iommu_init_table(&window->table, iommu->nid, 0, 0);
> +     if (!iommu_init_table(&window->table, iommu->nid, 0, 0))
> +             panic("Failed to initialize iommu table");
>  
>       pr_debug("\tioid      %d\n", window->ioid);
>       pr_debug("\tblocksize %ld\n", window->table.it_blocksize);
> diff --git a/arch/powerpc/platforms/pasemi/iommu.c 
> b/arch/powerpc/platforms/pasemi/iommu.c
> index b500a6e47e6b..5be7242fbd86 100644
> --- a/arch/powerpc/platforms/pasemi/iommu.c
> +++ b/arch/powerpc/platforms/pasemi/iommu.c
> @@ -146,7 +146,9 @@ static void iommu_table_iobmap_setup(void)
>        */
>       iommu_table_iobmap.it_blocksize = 4;
>       iommu_table_iobmap.it_ops = &iommu_table_iobmap_ops;
> -     iommu_init_table(&iommu_table_iobmap, 0, 0, 0);
> +     if (!iommu_init_table(&iommu_table_iobmap, 0, 0, 0))
> +             panic("Failed to initialize iommu table");
> +
>       pr_debug(" <- %s\n", __func__);
>  }
>  
> diff --git a/arch/powerpc/platforms/powernv/pci-ioda.c 
> b/arch/powerpc/platforms/powernv/pci-ioda.c
> index f0f901683a2f..66c3c3337334 100644
> --- a/arch/powerpc/platforms/powernv/pci-ioda.c
> +++ b/arch/powerpc/platforms/powernv/pci-ioda.c
> @@ -1762,7 +1762,8 @@ static void pnv_pci_ioda1_setup_dma_pe(struct pnv_phb 
> *phb,
>       tbl->it_ops = &pnv_ioda1_iommu_ops;
>       pe->table_group.tce32_start = tbl->it_offset << tbl->it_page_shift;
>       pe->table_group.tce32_size = tbl->it_size << tbl->it_page_shift;
> -     iommu_init_table(tbl, phb->hose->node, 0, 0);
> +     if (!iommu_init_table(tbl, phb->hose->node, 0, 0))
> +             panic("Failed to initialize iommu table");
>  
>       pe->dma_setup_done = true;
>       return;
> @@ -1930,16 +1931,16 @@ static long pnv_pci_ioda2_setup_default_config(struct 
> pnv_ioda_pe *pe)
>               res_start = pe->phb->ioda.m32_pci_base >> tbl->it_page_shift;
>               res_end = min(window_size, SZ_4G) >> tbl->it_page_shift;
>       }
> -     iommu_init_table(tbl, pe->phb->hose->node, res_start, res_end);
>  
> -     rc = pnv_pci_ioda2_set_window(&pe->table_group, 0, tbl);
> +     if (iommu_init_table(tbl, pe->phb->hose->node, res_start, res_end))
> +             rc = pnv_pci_ioda2_set_window(&pe->table_group, 0, tbl);
> +     else
> +             rc = -ENOMEM;
>       if (rc) {
> -             pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n",
> -                             rc);
> +             pe_err(pe, "Failed to configure 32-bit TCE table, err %ld\n", 
> rc);
>               iommu_tce_table_put(tbl);
> -             return rc;
> +             tbl = NULL; /* This clears iommu_table_base below */
>       }
> -
>       if (!pnv_iommu_bypass_disabled)
>               pnv_pci_ioda2_set_bypass(pe, true);
>  
> diff --git a/arch/powerpc/platforms/pseries/iommu.c 
> b/arch/powerpc/platforms/pseries/iommu.c
> index 9fc5217f0c8e..4d9ac1f181c2 100644
> --- a/arch/powerpc/platforms/pseries/iommu.c
> +++ b/arch/powerpc/platforms/pseries/iommu.c
> @@ -638,7 +638,8 @@ static void pci_dma_bus_setup_pSeries(struct pci_bus *bus)
>  
>       iommu_table_setparms(pci->phb, dn, tbl);
>       tbl->it_ops = &iommu_table_pseries_ops;
> -     iommu_init_table(tbl, pci->phb->node, 0, 0);
> +     if (!iommu_init_table(tbl, pci->phb->node, 0, 0))
> +             panic("Failed to initialize iommu table");
>  
>       /* Divide the rest (1.75GB) among the children */
>       pci->phb->dma_window_size = 0x80000000ul;
> @@ -720,7 +721,8 @@ static void pci_dma_bus_setup_pSeriesLP(struct pci_bus 
> *bus)
>               iommu_table_setparms_lpar(ppci->phb, pdn, tbl,
>                               ppci->table_group, dma_window);
>               tbl->it_ops = &iommu_table_lpar_multi_ops;
> -             iommu_init_table(tbl, ppci->phb->node, 0, 0);
> +             if (!iommu_init_table(tbl, ppci->phb->node, 0, 0))
> +                     panic("Failed to initialize iommu table");
>               iommu_register_group(ppci->table_group,
>                               pci_domain_nr(bus), 0);
>               pr_debug("  created table: %p\n", ppci->table_group);
> @@ -749,7 +751,9 @@ static void pci_dma_dev_setup_pSeries(struct pci_dev *dev)
>               tbl = PCI_DN(dn)->table_group->tables[0];
>               iommu_table_setparms(phb, dn, tbl);
>               tbl->it_ops = &iommu_table_pseries_ops;
> -             iommu_init_table(tbl, phb->node, 0, 0);
> +             if (!iommu_init_table(tbl, phb->node, 0, 0))
> +                     panic("Failed to initialize iommu table");
> +
>               set_iommu_table_base(&dev->dev, tbl);
>               return;
>       }
> diff --git a/arch/powerpc/sysdev/dart_iommu.c 
> b/arch/powerpc/sysdev/dart_iommu.c
> index 6b4a34b36d98..1d33b7a5ea83 100644
> --- a/arch/powerpc/sysdev/dart_iommu.c
> +++ b/arch/powerpc/sysdev/dart_iommu.c
> @@ -344,7 +344,8 @@ static void iommu_table_dart_setup(void)
>       iommu_table_dart.it_index = 0;
>       iommu_table_dart.it_blocksize = 1;
>       iommu_table_dart.it_ops = &iommu_dart_ops;
> -     iommu_init_table(&iommu_table_dart, -1, 0, 0);
> +     if (!iommu_init_table(&iommu_table_dart, -1, 0, 0))
> +             panic("Failed to initialize iommu table");
>  
>       /* Reserve the last page of the DART to avoid possible prefetch
>        * past the DART mapped area

-- 
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