Message ID | 20191014183108.24804-5-nsaenzjulienne@suse.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | ARM: Raspberry Pi 4 DMA support | expand |
On Mon, Oct 14, 2019 at 08:31:06PM +0200, Nicolas Saenz Julienne wrote: > The Raspberry Pi 4 has a 1GB ZONE_DMA area starting at address > 0x00000000 and a mapping between physical and DMA memory offset by > 0xc0000000. It transpires that, on non LPAE systems, any attempt to > translate physical addresses outside of ZONE_DMA will result in an > overflow. The resulting DMA addresses will not be detected by arm's > dma_capable() as they still fit in the device's DMA mask. > > Fix this by failing to validate a DMA address smaller than the lowest > possible DMA address. I think the main problem here is that arm doesn't respect the bus_dma_mask. If you replace the arm version of dma_capable with the generic one, does that fi the issue for you as well? We need to untangle the various macros arm uses for the direct mapping and eventually we should be able to use the linux/dma-direct.h helpers directly. Here is a branch with some simple preps I had. Freshly rebased, not actually tested: http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/arm-generic-dma-preps
On Tue, 2019-10-15 at 03:23 -0700, Christoph Hellwig wrote: > On Mon, Oct 14, 2019 at 08:31:06PM +0200, Nicolas Saenz Julienne wrote: > > The Raspberry Pi 4 has a 1GB ZONE_DMA area starting at address > > 0x00000000 and a mapping between physical and DMA memory offset by > > 0xc0000000. It transpires that, on non LPAE systems, any attempt to > > translate physical addresses outside of ZONE_DMA will result in an > > overflow. The resulting DMA addresses will not be detected by arm's > > dma_capable() as they still fit in the device's DMA mask. > > > > Fix this by failing to validate a DMA address smaller than the lowest > > possible DMA address. > > I think the main problem here is that arm doesn't respect the > bus_dma_mask. If you replace the arm version of dma_capable with > the generic one, does that fi the issue for you as well? Yeah, that was my fist thought too, but it doesn't help. So with RPi4's DMA mapping: soc { dma-ranges = <0xc0000000 0x0 0x00000000 0x3c000000>; [...] }; You'll get a 32bit bus dma map (log2i(0xc0000000 + 0x3c000000) + 1 = 32). Trouble is, taking into account arm's multi_v7_defconfig uses 32bit addresses, most phys_to_dma() translations are likely to overflow. For example phys 0x60000000 will be translated to DMA 0x20000000, which is no good. No mask is going to catch this, and both dma_capable() implementations will fail. > We need to untangle the various macros arm uses for the direct mapping > and eventually we should be able to use the linux/dma-direct.h helpers > directly. Here is a branch with some simple preps I had. Freshly > rebased, not actually tested: > > http://git.infradead.org/users/hch/misc.git/shortlog/refs/heads/arm-generic-dma-preps Noted, looks good to me. Actually, an alternative to this patch would be to kill all custom dma_capable() implementations, which are mostly redundant, and add these extra checks conditional to the DMA address size in the generic version. I'll try to respin this if I manage to understand what's going on with x86/sta211-fixup.c.
diff --git a/arch/arm/include/asm/dma-direct.h b/arch/arm/include/asm/dma-direct.h index b67e5fc1fe43..ee8ad47a14e3 100644 --- a/arch/arm/include/asm/dma-direct.h +++ b/arch/arm/include/asm/dma-direct.h @@ -2,6 +2,8 @@ #ifndef ASM_ARM_DMA_DIRECT_H #define ASM_ARM_DMA_DIRECT_H 1 +#include <linux/memblock.h> + static inline dma_addr_t __phys_to_dma(struct device *dev, phys_addr_t paddr) { unsigned int offset = paddr & ~PAGE_MASK; @@ -21,6 +23,10 @@ static inline bool dma_capable(struct device *dev, dma_addr_t addr, size_t size) if (!dev->dma_mask) return 0; + /* Check if address overflowed */ + if (addr < __phys_to_dma(dev, PFN_UP(min_low_pfn))) + return 0; + mask = *dev->dma_mask; limit = (mask + 1) & ~mask;
The Raspberry Pi 4 has a 1GB ZONE_DMA area starting at address 0x00000000 and a mapping between physical and DMA memory offset by 0xc0000000. It transpires that, on non LPAE systems, any attempt to translate physical addresses outside of ZONE_DMA will result in an overflow. The resulting DMA addresses will not be detected by arm's dma_capable() as they still fit in the device's DMA mask. Fix this by failing to validate a DMA address smaller than the lowest possible DMA address. Signed-off-by: Nicolas Saenz Julienne <nsaenzjulienne@suse.de> --- arch/arm/include/asm/dma-direct.h | 6 ++++++ 1 file changed, 6 insertions(+)