diff options
Diffstat (limited to 'kernel/dma/mapping.c')
-rw-r--r-- | kernel/dma/mapping.c | 32 |
1 files changed, 29 insertions, 3 deletions
diff --git a/kernel/dma/mapping.c b/kernel/dma/mapping.c index 1f628e7ac709..b0038ca3aa92 100644 --- a/kernel/dma/mapping.c +++ b/kernel/dma/mapping.c | |||
@@ -116,11 +116,16 @@ int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt, | |||
116 | int ret; | 116 | int ret; |
117 | 117 | ||
118 | if (!dev_is_dma_coherent(dev)) { | 118 | if (!dev_is_dma_coherent(dev)) { |
119 | unsigned long pfn; | ||
120 | |||
119 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) | 121 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) |
120 | return -ENXIO; | 122 | return -ENXIO; |
121 | 123 | ||
122 | page = pfn_to_page(arch_dma_coherent_to_pfn(dev, cpu_addr, | 124 | /* If the PFN is not valid, we do not have a struct page */ |
123 | dma_addr)); | 125 | pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); |
126 | if (!pfn_valid(pfn)) | ||
127 | return -ENXIO; | ||
128 | page = pfn_to_page(pfn); | ||
124 | } else { | 129 | } else { |
125 | page = virt_to_page(cpu_addr); | 130 | page = virt_to_page(cpu_addr); |
126 | } | 131 | } |
@@ -145,6 +150,23 @@ int dma_get_sgtable_attrs(struct device *dev, struct sg_table *sgt, | |||
145 | } | 150 | } |
146 | EXPORT_SYMBOL(dma_get_sgtable_attrs); | 151 | EXPORT_SYMBOL(dma_get_sgtable_attrs); |
147 | 152 | ||
153 | #ifdef CONFIG_MMU | ||
154 | /* | ||
155 | * Return the page attributes used for mapping dma_alloc_* memory, either in | ||
156 | * kernel space if remapping is needed, or to userspace through dma_mmap_*. | ||
157 | */ | ||
158 | pgprot_t dma_pgprot(struct device *dev, pgprot_t prot, unsigned long attrs) | ||
159 | { | ||
160 | if (dev_is_dma_coherent(dev) || | ||
161 | (IS_ENABLED(CONFIG_DMA_NONCOHERENT_CACHE_SYNC) && | ||
162 | (attrs & DMA_ATTR_NON_CONSISTENT))) | ||
163 | return prot; | ||
164 | if (IS_ENABLED(CONFIG_ARCH_HAS_DMA_MMAP_PGPROT)) | ||
165 | return arch_dma_mmap_pgprot(dev, prot, attrs); | ||
166 | return pgprot_noncached(prot); | ||
167 | } | ||
168 | #endif /* CONFIG_MMU */ | ||
169 | |||
148 | /* | 170 | /* |
149 | * Create userspace mapping for the DMA-coherent memory. | 171 | * Create userspace mapping for the DMA-coherent memory. |
150 | */ | 172 | */ |
@@ -159,7 +181,7 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, | |||
159 | unsigned long pfn; | 181 | unsigned long pfn; |
160 | int ret = -ENXIO; | 182 | int ret = -ENXIO; |
161 | 183 | ||
162 | vma->vm_page_prot = arch_dma_mmap_pgprot(dev, vma->vm_page_prot, attrs); | 184 | vma->vm_page_prot = dma_pgprot(dev, vma->vm_page_prot, attrs); |
163 | 185 | ||
164 | if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) | 186 | if (dma_mmap_from_dev_coherent(dev, vma, cpu_addr, size, &ret)) |
165 | return ret; | 187 | return ret; |
@@ -170,7 +192,11 @@ int dma_common_mmap(struct device *dev, struct vm_area_struct *vma, | |||
170 | if (!dev_is_dma_coherent(dev)) { | 192 | if (!dev_is_dma_coherent(dev)) { |
171 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) | 193 | if (!IS_ENABLED(CONFIG_ARCH_HAS_DMA_COHERENT_TO_PFN)) |
172 | return -ENXIO; | 194 | return -ENXIO; |
195 | |||
196 | /* If the PFN is not valid, we do not have a struct page */ | ||
173 | pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); | 197 | pfn = arch_dma_coherent_to_pfn(dev, cpu_addr, dma_addr); |
198 | if (!pfn_valid(pfn)) | ||
199 | return -ENXIO; | ||
174 | } else { | 200 | } else { |
175 | pfn = page_to_pfn(virt_to_page(cpu_addr)); | 201 | pfn = page_to_pfn(virt_to_page(cpu_addr)); |
176 | } | 202 | } |