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 <aik@xxxxxxxxx> Reviewed-by: David Gibson <david@xxxxxxxxxxxxxxxxxxxxx> > --- > 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