Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

powerpc/pseries/iommu: enable_ddw incorrectly returns direct mapping for SR-IOV device

When a device is initialized, the driver invokes dma_supported() twice -
first for streaming mappings followed by coherent mappings. For an
SR-IOV device, default window is deleted and DDW created. With vPMEM
enabled, TCE mappings are dynamically created for both vPMEM and SR-IOV
device. There are no direct mappings.

First time when dma_supported() is called with 64 bit mask, DDW is created
and marked as dynamic window. The second time dma_supported() is called,
enable_ddw() finds existing window for the device and incorrectly returns
it as "direct mapping".

This only happens when size of DDW is big enough to map max LPAR memory.

This results in streaming TCEs to not get dynamically mapped, since code
incorrently assumes these are already pre-mapped. The adapter initially
comes up but goes down due to EEH.

Fixes: 381ceda88c4c ("powerpc/pseries/iommu: Make use of DDW for indirect mapping")
Cc: stable@vger.kernel.org # v5.15+
Signed-off-by: Gaurav Batra <gbatra@linux.vnet.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20231003030802.47914-1-gbatra@linux.vnet.ibm.com

authored by

Gaurav Batra and committed by
Michael Ellerman
3bf983e4 efce8422

+4 -4
+4 -4
arch/powerpc/platforms/pseries/iommu.c
··· 914 914 return 0; 915 915 } 916 916 917 - static bool find_existing_ddw(struct device_node *pdn, u64 *dma_addr, int *window_shift) 917 + static bool find_existing_ddw(struct device_node *pdn, u64 *dma_addr, int *window_shift, 918 + bool *direct_mapping) 918 919 { 919 920 struct dma_win *window; 920 921 const struct dynamic_dma_window_prop *dma64; ··· 928 927 dma64 = window->prop; 929 928 *dma_addr = be64_to_cpu(dma64->dma_base); 930 929 *window_shift = be32_to_cpu(dma64->window_shift); 930 + *direct_mapping = window->direct; 931 931 found = true; 932 932 break; 933 933 } ··· 1272 1270 1273 1271 mutex_lock(&dma_win_init_mutex); 1274 1272 1275 - if (find_existing_ddw(pdn, &dev->dev.archdata.dma_offset, &len)) { 1276 - direct_mapping = (len >= max_ram_len); 1273 + if (find_existing_ddw(pdn, &dev->dev.archdata.dma_offset, &len, &direct_mapping)) 1277 1274 goto out_unlock; 1278 - } 1279 1275 1280 1276 /* 1281 1277 * If we already went through this for a previous function of