| From 302c759318099f4625360b90947f6a6397d995c0 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Tue, 5 Jul 2022 11:26:34 +0300 |
| Subject: intel_th: msu: Fix vmalloced buffers |
| |
| From: Alexander Shishkin <alexander.shishkin@linux.intel.com> |
| |
| [ Upstream commit ac12ad3ccf6d386e64a9d6a890595a2509d24edd ] |
| |
| After commit f5ff79fddf0e ("dma-mapping: remove CONFIG_DMA_REMAP") there's |
| a chance of DMA buffer getting allocated via vmalloc(), which messes up |
| the mmapping code: |
| |
| > RIP: msc_mmap_fault [intel_th_msu] |
| > Call Trace: |
| > <TASK> |
| > __do_fault |
| > do_fault |
| ... |
| |
| Fix this by accounting for vmalloc possibility. |
| |
| Fixes: ba39bd830605 ("intel_th: msu: Switch over to scatterlist") |
| Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> |
| Signed-off-by: Alexander Shishkin <alexander.shishkin@linux.intel.com> |
| Link: https://lore.kernel.org/r/20220705082637.59979-4-alexander.shishkin@linux.intel.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/hwtracing/intel_th/msu.c | 14 ++++++++++++-- |
| 1 file changed, 12 insertions(+), 2 deletions(-) |
| |
| diff --git a/drivers/hwtracing/intel_th/msu.c b/drivers/hwtracing/intel_th/msu.c |
| index 3cd2489d398c..640b0aae7eb4 100644 |
| --- a/drivers/hwtracing/intel_th/msu.c |
| +++ b/drivers/hwtracing/intel_th/msu.c |
| @@ -1050,6 +1050,16 @@ msc_buffer_set_uc(struct msc_window *win, unsigned int nr_segs) {} |
| static inline void msc_buffer_set_wb(struct msc_window *win) {} |
| #endif /* CONFIG_X86 */ |
| |
| +static struct page *msc_sg_page(struct scatterlist *sg) |
| +{ |
| + void *addr = sg_virt(sg); |
| + |
| + if (is_vmalloc_addr(addr)) |
| + return vmalloc_to_page(addr); |
| + |
| + return sg_page(sg); |
| +} |
| + |
| /** |
| * msc_buffer_win_alloc() - alloc a window for a multiblock mode |
| * @msc: MSC device |
| @@ -1122,7 +1132,7 @@ static void __msc_buffer_win_free(struct msc *msc, struct msc_window *win) |
| int i; |
| |
| for_each_sg(win->sgt->sgl, sg, win->nr_segs, i) { |
| - struct page *page = sg_page(sg); |
| + struct page *page = msc_sg_page(sg); |
| |
| page->mapping = NULL; |
| dma_free_coherent(msc_dev(win->msc)->parent->parent, PAGE_SIZE, |
| @@ -1384,7 +1394,7 @@ static struct page *msc_buffer_get_page(struct msc *msc, unsigned long pgoff) |
| pgoff -= win->pgoff; |
| |
| for_each_sg(win->sgt->sgl, sg, win->nr_segs, blk) { |
| - struct page *page = sg_page(sg); |
| + struct page *page = msc_sg_page(sg); |
| size_t pgsz = PFN_DOWN(sg->length); |
| |
| if (pgoff < pgsz) |
| -- |
| 2.35.1 |
| |