Skip to content

Commit d61cd13

Browse files
Gaurav Batrampe
authored andcommitted
powerpc/iommu: TCEs are incorrectly manipulated with DLPAR add/remove of memory
When memory is dynamically added/removed, iommu_mem_notifier() is invoked. This routine traverses through all the DMA windows (DDW only, not default windows) to add/remove "direct" TCE mappings. The routines for this purpose are tce_clearrange_multi_pSeriesLP() and tce_clearrange_multi_pSeriesLP(). Both these routines are designed for Direct mapped DMA windows only. The issue is that there could be some DMA windows in the list which are not "direct" mapped. Calling these routines will either, 1) remove some dynamically mapped TCEs, Or 2) try to add TCEs which are out of bounds and HCALL returns H_PARAMETER Here are the side affects when these routines are incorrectly invoked for "dynamically" mapped DMA windows. tce_setrange_multi_pSeriesLP() This adds direct mapped TCEs. Now, this could invoke HCALL to add TCEs with out-of-bound range. In this scenario, HCALL will return H_PARAMETER and DLAR ADD of memory will fail. tce_clearrange_multi_pSeriesLP() This will remove range of TCEs. The TCE range that is calculated, depending on the memory range being added, could infact be mapping some other memory address (for dynamic DMA window scenario). This will wipe out those TCEs. The solution is for iommu_mem_notifier() to only invoke these routines for "direct" mapped DMA windows. Signed-off-by: Gaurav Batra <[email protected]> Reviewed-by: Brian King <[email protected]> [mpe: Initialise direct at allocation time in ddw_list_new_entry()] Signed-off-by: Michael Ellerman <[email protected]> Link: https://msgid.link/[email protected]
1 parent bfd8d98 commit d61cd13

File tree

1 file changed

+14
-4
lines changed
  • arch/powerpc/platforms/pseries

1 file changed

+14
-4
lines changed

arch/powerpc/platforms/pseries/iommu.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,7 @@ struct dynamic_dma_window_prop {
372372
struct dma_win {
373373
struct device_node *device;
374374
const struct dynamic_dma_window_prop *prop;
375+
bool direct;
375376
struct list_head list;
376377
};
377378

@@ -948,6 +949,7 @@ static struct dma_win *ddw_list_new_entry(struct device_node *pdn,
948949

949950
window->device = pdn;
950951
window->prop = dma64;
952+
window->direct = false;
951953

952954
return window;
953955
}
@@ -1418,6 +1420,8 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
14181420
goto out_del_prop;
14191421

14201422
if (direct_mapping) {
1423+
window->direct = true;
1424+
14211425
/* DDW maps the whole partition, so enable direct DMA mapping */
14221426
ret = walk_system_ram_range(0, memblock_end_of_DRAM() >> PAGE_SHIFT,
14231427
win64->value, tce_setrange_multi_pSeriesLP_walk);
@@ -1434,6 +1438,8 @@ static bool enable_ddw(struct pci_dev *dev, struct device_node *pdn)
14341438
int i;
14351439
unsigned long start = 0, end = 0;
14361440

1441+
window->direct = false;
1442+
14371443
for (i = 0; i < ARRAY_SIZE(pci->phb->mem_resources); i++) {
14381444
const unsigned long mask = IORESOURCE_MEM_64 | IORESOURCE_MEM;
14391445

@@ -1596,8 +1602,10 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
15961602
case MEM_GOING_ONLINE:
15971603
spin_lock(&dma_win_list_lock);
15981604
list_for_each_entry(window, &dma_win_list, list) {
1599-
ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn,
1600-
arg->nr_pages, window->prop);
1605+
if (window->direct) {
1606+
ret |= tce_setrange_multi_pSeriesLP(arg->start_pfn,
1607+
arg->nr_pages, window->prop);
1608+
}
16011609
/* XXX log error */
16021610
}
16031611
spin_unlock(&dma_win_list_lock);
@@ -1606,8 +1614,10 @@ static int iommu_mem_notifier(struct notifier_block *nb, unsigned long action,
16061614
case MEM_OFFLINE:
16071615
spin_lock(&dma_win_list_lock);
16081616
list_for_each_entry(window, &dma_win_list, list) {
1609-
ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn,
1610-
arg->nr_pages, window->prop);
1617+
if (window->direct) {
1618+
ret |= tce_clearrange_multi_pSeriesLP(arg->start_pfn,
1619+
arg->nr_pages, window->prop);
1620+
}
16111621
/* XXX log error */
16121622
}
16131623
spin_unlock(&dma_win_list_lock);

0 commit comments

Comments
 (0)