diff options
author | Lars-Peter Clausen <lars@metafoo.de> | 2014-12-03 10:07:28 -0500 |
---|---|---|
committer | Michal Simek <michal.simek@xilinx.com> | 2014-12-17 06:59:59 -0500 |
commit | 3a8e3265179b7e6394d7aab4d6df5651b49e7243 (patch) | |
tree | 82194a886cb05fe27ba3ddf0dca4ec05c3977e4a /arch/microblaze/mm | |
parent | b2776bf7149bddd1f4161f14f79520f17fc1d71d (diff) |
microblaze: Fix mmap for cache coherent memory
When running in non-cache coherent configuration the memory that was
allocated with dma_alloc_coherent() has a custom mapping and so there is no
1-to-1 relationship between the kernel virtual address and the PFN. This
means that virt_to_pfn() will not work correctly for those addresses and the
default mmap implementation in the form of dma_common_mmap() will map some
random, but not the requested, memory area.
Fix this by providing a custom mmap implementation that looks up the PFN
from the page table rather than using virt_to_pfn.
Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Diffstat (limited to 'arch/microblaze/mm')
-rw-r--r-- | arch/microblaze/mm/consistent.c | 25 |
1 files changed, 20 insertions, 5 deletions
diff --git a/arch/microblaze/mm/consistent.c b/arch/microblaze/mm/consistent.c index e10ad930895e..b06c3a7faf20 100644 --- a/arch/microblaze/mm/consistent.c +++ b/arch/microblaze/mm/consistent.c | |||
@@ -156,6 +156,25 @@ void *consistent_alloc(gfp_t gfp, size_t size, dma_addr_t *dma_handle) | |||
156 | } | 156 | } |
157 | EXPORT_SYMBOL(consistent_alloc); | 157 | EXPORT_SYMBOL(consistent_alloc); |
158 | 158 | ||
159 | #ifdef CONFIG_MMU | ||
160 | static pte_t *consistent_virt_to_pte(void *vaddr) | ||
161 | { | ||
162 | unsigned long addr = (unsigned long)vaddr; | ||
163 | |||
164 | return pte_offset_kernel(pmd_offset(pgd_offset_k(addr), addr), addr); | ||
165 | } | ||
166 | |||
167 | unsigned long consistent_virt_to_pfn(void *vaddr) | ||
168 | { | ||
169 | pte_t *ptep = consistent_virt_to_pte(vaddr); | ||
170 | |||
171 | if (pte_none(*ptep) || !pte_present(*ptep)) | ||
172 | return 0; | ||
173 | |||
174 | return pte_pfn(*ptep); | ||
175 | } | ||
176 | #endif | ||
177 | |||
159 | /* | 178 | /* |
160 | * free page(s) as defined by the above mapping. | 179 | * free page(s) as defined by the above mapping. |
161 | */ | 180 | */ |
@@ -181,13 +200,9 @@ void consistent_free(size_t size, void *vaddr) | |||
181 | } while (size -= PAGE_SIZE); | 200 | } while (size -= PAGE_SIZE); |
182 | #else | 201 | #else |
183 | do { | 202 | do { |
184 | pte_t *ptep; | 203 | pte_t *ptep = consistent_virt_to_pte(vaddr); |
185 | unsigned long pfn; | 204 | unsigned long pfn; |
186 | 205 | ||
187 | ptep = pte_offset_kernel(pmd_offset(pgd_offset_k( | ||
188 | (unsigned int)vaddr), | ||
189 | (unsigned int)vaddr), | ||
190 | (unsigned int)vaddr); | ||
191 | if (!pte_none(*ptep) && pte_present(*ptep)) { | 206 | if (!pte_none(*ptep) && pte_present(*ptep)) { |
192 | pfn = pte_pfn(*ptep); | 207 | pfn = pte_pfn(*ptep); |
193 | pte_clear(&init_mm, (unsigned int)vaddr, ptep); | 208 | pte_clear(&init_mm, (unsigned int)vaddr, ptep); |