OSDN Git Service

dma-direct: reject too small dma masks
authorChristoph Hellwig <hch@lst.de>
Sun, 24 Dec 2017 14:04:32 +0000 (15:04 +0100)
committerChristoph Hellwig <hch@lst.de>
Mon, 15 Jan 2018 08:35:15 +0000 (09:35 +0100)
Signed-off-by: Christoph Hellwig <hch@lst.de>
Reviewed-by: Robin Murphy <robin.murphy@arm.com>
include/linux/dma-direct.h
lib/dma-direct.c

index 4788bf0..bcdb1a3 100644 (file)
@@ -42,5 +42,6 @@ void *dma_direct_alloc(struct device *dev, size_t size, dma_addr_t *dma_handle,
                gfp_t gfp, unsigned long attrs);
 void dma_direct_free(struct device *dev, size_t size, void *cpu_addr,
                dma_addr_t dma_addr, unsigned long attrs);
+int dma_direct_supported(struct device *dev, u64 mask);
 
 #endif /* _LINUX_DMA_DIRECT_H */
index 784a68d..40b1f92 100644 (file)
@@ -122,6 +122,24 @@ static int dma_direct_map_sg(struct device *dev, struct scatterlist *sgl,
        return nents;
 }
 
+int dma_direct_supported(struct device *dev, u64 mask)
+{
+#ifdef CONFIG_ZONE_DMA
+       if (mask < DMA_BIT_MASK(ARCH_ZONE_DMA_BITS))
+               return 0;
+#else
+       /*
+        * Because 32-bit DMA masks are so common we expect every architecture
+        * to be able to satisfy them - either by not supporting more physical
+        * memory, or by providing a ZONE_DMA32.  If neither is the case, the
+        * architecture needs to use an IOMMU instead of the direct mapping.
+        */
+       if (mask < DMA_BIT_MASK(32))
+               return 0;
+#endif
+       return 1;
+}
+
 static int dma_direct_mapping_error(struct device *dev, dma_addr_t dma_addr)
 {
        return dma_addr == DIRECT_MAPPING_ERROR;
@@ -132,6 +150,7 @@ const struct dma_map_ops dma_direct_ops = {
        .free                   = dma_direct_free,
        .map_page               = dma_direct_map_page,
        .map_sg                 = dma_direct_map_sg,
+       .dma_supported          = dma_direct_supported,
        .mapping_error          = dma_direct_mapping_error,
 };
 EXPORT_SYMBOL(dma_direct_ops);