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

dmaengine: idma64: Use actual device for DMA transfers

Intel IOMMU, when enabled, tries to find the domain of the device,
assuming it's a PCI one, during DMA operations, such as mapping or
unmapping. Since we are splitting the actual PCI device to couple of
children via MFD framework (see drivers/mfd/intel-lpss.c for details),
the DMA device appears to be a platform one, and thus not an actual one
that performs DMA. In a such situation IOMMU can't find or allocate
a proper domain for its operations. As a result, all DMA operations are
failed.

In order to fix this, supply parent of the platform device
to the DMA engine framework and fix filter functions accordingly.

We may rely on the fact that parent is a real PCI device, because no
other configuration is present in the wild.

Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Acked-by: Mark Brown <broonie@kernel.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [for tty parts]
Signed-off-by: Vinod Koul <vkoul@kernel.org>

authored by

Andy Shevchenko and committed by
Vinod Koul
5ba846b1 9e98c678

+9 -10
+4 -2
drivers/dma/idma64.c
··· 592 592 idma64->dma.directions = BIT(DMA_DEV_TO_MEM) | BIT(DMA_MEM_TO_DEV); 593 593 idma64->dma.residue_granularity = DMA_RESIDUE_GRANULARITY_BURST; 594 594 595 - idma64->dma.dev = chip->dev; 595 + idma64->dma.dev = chip->sysdev; 596 596 597 597 dma_set_max_seg_size(idma64->dma.dev, IDMA64C_CTLH_BLOCK_TS_MASK); 598 598 ··· 632 632 { 633 633 struct idma64_chip *chip; 634 634 struct device *dev = &pdev->dev; 635 + struct device *sysdev = dev->parent; 635 636 struct resource *mem; 636 637 int ret; 637 638 ··· 649 648 if (IS_ERR(chip->regs)) 650 649 return PTR_ERR(chip->regs); 651 650 652 - ret = dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); 651 + ret = dma_coerce_mask_and_coherent(sysdev, DMA_BIT_MASK(64)); 653 652 if (ret) 654 653 return ret; 655 654 656 655 chip->dev = dev; 656 + chip->sysdev = sysdev; 657 657 658 658 ret = idma64_probe(chip); 659 659 if (ret)
+2
drivers/dma/idma64.h
··· 216 216 /** 217 217 * struct idma64_chip - representation of iDMA 64-bit controller hardware 218 218 * @dev: struct device of the DMA controller 219 + * @sysdev: struct device of the physical device that does DMA 219 220 * @irq: irq line 220 221 * @regs: memory mapped I/O space 221 222 * @idma64: struct idma64 that is filed by idma64_probe() 222 223 */ 223 224 struct idma64_chip { 224 225 struct device *dev; 226 + struct device *sysdev; 225 227 int irq; 226 228 void __iomem *regs; 227 229 struct idma64 *idma64;
+1 -6
drivers/spi/spi-pxa2xx.c
··· 1487 1487 1488 1488 static bool pxa2xx_spi_idma_filter(struct dma_chan *chan, void *param) 1489 1489 { 1490 - struct device *dev = param; 1491 - 1492 - if (dev != chan->device->dev->parent) 1493 - return false; 1494 - 1495 - return true; 1490 + return param == chan->device->dev; 1496 1491 } 1497 1492 1498 1493 #endif /* CONFIG_PCI */
+2 -2
drivers/tty/serial/8250/8250_dw.c
··· 365 365 366 366 static bool dw8250_idma_filter(struct dma_chan *chan, void *param) 367 367 { 368 - return param == chan->device->dev->parent; 368 + return param == chan->device->dev; 369 369 } 370 370 371 371 /* ··· 434 434 data->uart_16550_compatible = true; 435 435 } 436 436 437 - /* Platforms with iDMA */ 437 + /* Platforms with iDMA 64-bit */ 438 438 if (platform_get_resource_byname(to_platform_device(p->dev), 439 439 IORESOURCE_MEM, "lpss_priv")) { 440 440 data->dma.rx_param = p->dev->parent;