Message ID | 1651845086-16535-1-git-send-email-quic_sibis@quicinc.com (mailing list archive) |
---|---|
State | Superseded |
Headers | show |
Series | remoteproc: qcom_q6v5_mss: map/unmap metadata region before/after use | expand |
On Fri, May 06, 2022 at 07:21:26PM +0530, Sibi Sankar wrote: > The application processor accessing the dynamically assigned metadata > region after assigning it to the remote Q6 would lead to an XPU violation. > Fix this by un-mapping the metadata region post firmware header copy. The > metadata region is freed only after the modem Q6 is done with fw header > authentication. > > Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com> Should this have a 'Fixes:' tag? > --- > drivers/remoteproc/qcom_q6v5_mss.c | 43 +++++++++++++++++++++++++++++++------- > 1 file changed, 35 insertions(+), 8 deletions(-) > > diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c > index af217de75e4d..eb34a258b67b 100644 > --- a/drivers/remoteproc/qcom_q6v5_mss.c > +++ b/drivers/remoteproc/qcom_q6v5_mss.c > @@ -10,6 +10,7 @@ > #include <linux/clk.h> > #include <linux/delay.h> > #include <linux/devcoredump.h> > +#include <linux/dma-map-ops.h> > #include <linux/dma-mapping.h> > #include <linux/interrupt.h> > #include <linux/kernel.h> > @@ -932,27 +933,52 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc, > static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, > const char *fw_name) > { > - unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; > + unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING; > + unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS; > + struct page **pages; > + struct page *page; > dma_addr_t phys; > void *metadata; > int mdata_perm; > int xferop_ret; > size_t size; > - void *ptr; > + void *vaddr; > + int count; > int ret; > + int i; > > metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev); > if (IS_ERR(metadata)) > return PTR_ERR(metadata); > > - ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); > - if (!ptr) { > - kfree(metadata); > + page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); > + if (!page) { > dev_err(qproc->dev, "failed to allocate mdt buffer\n"); > - return -ENOMEM; > + ret = -ENOMEM; > + goto free_metadata; > + } > + > + count = PAGE_ALIGN(size) >> PAGE_SHIFT; > + pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL); > + if (!pages) { > + ret = -ENOMEM; > + goto free_metadata; > } > > - memcpy(ptr, metadata, size); > + for (i = 0; i < count; i++) > + pages[i] = nth_page(page, i); > + > + vaddr = vmap(pages, count, flags, dma_pgprot(qproc->dev, PAGE_KERNEL, dma_attrs)); > + kfree(pages); > + if (!vaddr) { > + dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size); > + ret = -EBUSY; > + goto free_metadata; > + } > + > + memcpy(vaddr, metadata, size); > + > + vunmap(vaddr); > > /* Hypervisor mapping to access metadata by modem */ > mdata_perm = BIT(QCOM_SCM_VMID_HLOS); > @@ -982,7 +1008,8 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, > "mdt buffer not reclaimed system may become unstable\n"); > > free_dma_attrs: > - dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); > + dma_free_attrs(qproc->dev, size, page, phys, dma_attrs); > +free_metadata: > kfree(metadata); > > return ret < 0 ? ret : 0; > -- > 2.7.4 >
Hi Sibi,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on remoteproc/rproc-next]
[also build test ERROR on soc/for-next linux/master linus/master v5.18-rc5 next-20220506]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Sibi-Sankar/remoteproc-qcom_q6v5_mss-map-unmap-metadata-region-before-after-use/20220506-215346
base: git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
config: arm-defconfig (https://download.01.org/0day-ci/archive/20220507/202205070616.N8LRPhTW-lkp@intel.com/config)
compiler: arm-linux-gnueabi-gcc (GCC) 11.3.0
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# https://github.com/intel-lab-lkp/linux/commit/7a6766ecbb124cd4e41ae630420109330879239d
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Sibi-Sankar/remoteproc-qcom_q6v5_mss-map-unmap-metadata-region-before-after-use/20220506-215346
git checkout 7a6766ecbb124cd4e41ae630420109330879239d
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=gcc-11.3.0 make.cross W=1 O=build_dir ARCH=arm SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>, old ones prefixed by <<):
>> ERROR: modpost: "dma_pgprot" [drivers/remoteproc/qcom_q6v5_mss.ko] undefined!
Hi Sibi,
Thank you for the patch! Yet something to improve:
[auto build test ERROR on remoteproc/rproc-next]
[also build test ERROR on soc/for-next linux/master linus/master v5.18-rc5]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]
url: https://github.com/intel-lab-lkp/linux/commits/Sibi-Sankar/remoteproc-qcom_q6v5_mss-map-unmap-metadata-region-before-after-use/20220506-215346
base: git://git.kernel.org/pub/scm/linux/kernel/git/remoteproc/linux.git rproc-next
config: arm64-randconfig-r021-20220506 (https://download.01.org/0day-ci/archive/20220507/202205070739.ug3ojjmp-lkp@intel.com/config)
compiler: clang version 15.0.0 (https://github.com/llvm/llvm-project 5e004fb787698440a387750db7f8028e7cb14cfc)
reproduce (this is a W=1 build):
wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
chmod +x ~/bin/make.cross
# install arm64 cross compiling tool for clang build
# apt-get install binutils-aarch64-linux-gnu
# https://github.com/intel-lab-lkp/linux/commit/7a6766ecbb124cd4e41ae630420109330879239d
git remote add linux-review https://github.com/intel-lab-lkp/linux
git fetch --no-tags linux-review Sibi-Sankar/remoteproc-qcom_q6v5_mss-map-unmap-metadata-region-before-after-use/20220506-215346
git checkout 7a6766ecbb124cd4e41ae630420109330879239d
# save the config file
mkdir build_dir && cp config build_dir/.config
COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross W=1 O=build_dir ARCH=arm64 SHELL=/bin/bash
If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>
All errors (new ones prefixed by >>, old ones prefixed by <<):
>> ERROR: modpost: "dma_pgprot" [drivers/remoteproc/qcom_q6v5_mss.ko] undefined!
Hey Matthias, Thanks for taking time to review the patch. On 5/6/22 11:37 PM, Matthias Kaehlcke wrote: > On Fri, May 06, 2022 at 07:21:26PM +0530, Sibi Sankar wrote: >> The application processor accessing the dynamically assigned metadata >> region after assigning it to the remote Q6 would lead to an XPU violation. >> Fix this by un-mapping the metadata region post firmware header copy. The >> metadata region is freed only after the modem Q6 is done with fw header >> authentication. >> >> Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com> > > Should this have a 'Fixes:' tag It ideally should have but similar to what we did for mba and mpss region map/unmap, it would be a ugly backport since it would point to the very first commit. We can agree to do a backport if it's ever reported upstream on any of the older SoCs. -Sibi > >> --- >> drivers/remoteproc/qcom_q6v5_mss.c | 43 +++++++++++++++++++++++++++++++------- >> 1 file changed, 35 insertions(+), 8 deletions(-) >> >> diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c >> index af217de75e4d..eb34a258b67b 100644 >> --- a/drivers/remoteproc/qcom_q6v5_mss.c >> +++ b/drivers/remoteproc/qcom_q6v5_mss.c >> @@ -10,6 +10,7 @@ >> #include <linux/clk.h> >> #include <linux/delay.h> >> #include <linux/devcoredump.h> >> +#include <linux/dma-map-ops.h> >> #include <linux/dma-mapping.h> >> #include <linux/interrupt.h> >> #include <linux/kernel.h> >> @@ -932,27 +933,52 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc, >> static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, >> const char *fw_name) >> { >> - unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; >> + unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING; >> + unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS; >> + struct page **pages; >> + struct page *page; >> dma_addr_t phys; >> void *metadata; >> int mdata_perm; >> int xferop_ret; >> size_t size; >> - void *ptr; >> + void *vaddr; >> + int count; >> int ret; >> + int i; >> >> metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev); >> if (IS_ERR(metadata)) >> return PTR_ERR(metadata); >> >> - ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); >> - if (!ptr) { >> - kfree(metadata); >> + page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); >> + if (!page) { >> dev_err(qproc->dev, "failed to allocate mdt buffer\n"); >> - return -ENOMEM; >> + ret = -ENOMEM; >> + goto free_metadata; >> + } >> + >> + count = PAGE_ALIGN(size) >> PAGE_SHIFT; >> + pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL); >> + if (!pages) { >> + ret = -ENOMEM; >> + goto free_metadata; >> } >> >> - memcpy(ptr, metadata, size); >> + for (i = 0; i < count; i++) >> + pages[i] = nth_page(page, i); >> + >> + vaddr = vmap(pages, count, flags, dma_pgprot(qproc->dev, PAGE_KERNEL, dma_attrs)); >> + kfree(pages); >> + if (!vaddr) { >> + dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size); >> + ret = -EBUSY; >> + goto free_metadata; >> + } >> + >> + memcpy(vaddr, metadata, size); >> + >> + vunmap(vaddr); >> >> /* Hypervisor mapping to access metadata by modem */ >> mdata_perm = BIT(QCOM_SCM_VMID_HLOS); >> @@ -982,7 +1008,8 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, >> "mdt buffer not reclaimed system may become unstable\n"); >> >> free_dma_attrs: >> - dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); >> + dma_free_attrs(qproc->dev, size, page, phys, dma_attrs); >> +free_metadata: >> kfree(metadata); >> >> return ret < 0 ? ret : 0; >> -- >> 2.7.4 >>
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c index af217de75e4d..eb34a258b67b 100644 --- a/drivers/remoteproc/qcom_q6v5_mss.c +++ b/drivers/remoteproc/qcom_q6v5_mss.c @@ -10,6 +10,7 @@ #include <linux/clk.h> #include <linux/delay.h> #include <linux/devcoredump.h> +#include <linux/dma-map-ops.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/kernel.h> @@ -932,27 +933,52 @@ static void q6v5proc_halt_axi_port(struct q6v5 *qproc, static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, const char *fw_name) { - unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS; + unsigned long dma_attrs = DMA_ATTR_FORCE_CONTIGUOUS | DMA_ATTR_NO_KERNEL_MAPPING; + unsigned long flags = VM_DMA_COHERENT | VM_FLUSH_RESET_PERMS; + struct page **pages; + struct page *page; dma_addr_t phys; void *metadata; int mdata_perm; int xferop_ret; size_t size; - void *ptr; + void *vaddr; + int count; int ret; + int i; metadata = qcom_mdt_read_metadata(fw, &size, fw_name, qproc->dev); if (IS_ERR(metadata)) return PTR_ERR(metadata); - ptr = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); - if (!ptr) { - kfree(metadata); + page = dma_alloc_attrs(qproc->dev, size, &phys, GFP_KERNEL, dma_attrs); + if (!page) { dev_err(qproc->dev, "failed to allocate mdt buffer\n"); - return -ENOMEM; + ret = -ENOMEM; + goto free_metadata; + } + + count = PAGE_ALIGN(size) >> PAGE_SHIFT; + pages = kmalloc_array(count, sizeof(struct page *), GFP_KERNEL); + if (!pages) { + ret = -ENOMEM; + goto free_metadata; } - memcpy(ptr, metadata, size); + for (i = 0; i < count; i++) + pages[i] = nth_page(page, i); + + vaddr = vmap(pages, count, flags, dma_pgprot(qproc->dev, PAGE_KERNEL, dma_attrs)); + kfree(pages); + if (!vaddr) { + dev_err(qproc->dev, "unable to map memory region: %pa+%zx\n", &phys, size); + ret = -EBUSY; + goto free_metadata; + } + + memcpy(vaddr, metadata, size); + + vunmap(vaddr); /* Hypervisor mapping to access metadata by modem */ mdata_perm = BIT(QCOM_SCM_VMID_HLOS); @@ -982,7 +1008,8 @@ static int q6v5_mpss_init_image(struct q6v5 *qproc, const struct firmware *fw, "mdt buffer not reclaimed system may become unstable\n"); free_dma_attrs: - dma_free_attrs(qproc->dev, size, ptr, phys, dma_attrs); + dma_free_attrs(qproc->dev, size, page, phys, dma_attrs); +free_metadata: kfree(metadata); return ret < 0 ? ret : 0;
The application processor accessing the dynamically assigned metadata region after assigning it to the remote Q6 would lead to an XPU violation. Fix this by un-mapping the metadata region post firmware header copy. The metadata region is freed only after the modem Q6 is done with fw header authentication. Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com> --- drivers/remoteproc/qcom_q6v5_mss.c | 43 +++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-)