firmware: qcom_scm: fix error for incompatible pointer
diff mbox series

Message ID 20190719134303.7617-1-minwoo.im.dev@gmail.com
State New
Headers show
Series
  • firmware: qcom_scm: fix error for incompatible pointer
Related show

Commit Message

Minwoo Im July 19, 2019, 1:43 p.m. UTC
The following error can happen when trying to build it:

```
drivers/firmware/qcom_scm.c: In function ‘qcom_scm_assign_mem’:
drivers/firmware/qcom_scm.c:460:47: error: passing argument 3 of ‘dma_alloc_coherent’ from incompatible pointer type [-Werror=incompatible-pointer-types]
  ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
                                               ^
In file included from drivers/firmware/qcom_scm.c:12:0:
./include/linux/dma-mapping.h:636:21: note: expected ‘dma_addr_t * {aka long long unsigned int *}’ but argument is of type ‘phys_addr_t * {aka unsigned int *}’
 static inline void *dma_alloc_coherent(struct device *dev, size_t size,
                     ^~~~~~~~~~~~~~~~~~
```

We just can cast phys_addr_t to dma_addr_t here.

Cc: Andy Gross <agross@kernel.org>
Cc: David Brown <david.brown@linaro.org>
Signed-off-by: Minwoo Im <minwoo.im.dev@gmail.com>
---
 drivers/firmware/qcom_scm.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Marc Gonzalez July 22, 2019, 8:38 a.m. UTC | #1
Adding people who have worked on drivers/firmware/qcom_scm.c or DMA

On 19/07/2019 15:43, Minwoo Im wrote:

> The following error can happen when trying to build it:
> 
> ```
> drivers/firmware/qcom_scm.c: In function ‘qcom_scm_assign_mem’:
> drivers/firmware/qcom_scm.c:460:47: error: passing argument 3 of ‘dma_alloc_coherent’ from incompatible pointer type [-Werror=incompatible-pointer-types]
>   ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
>                                                ^
> In file included from drivers/firmware/qcom_scm.c:12:0:
> ./include/linux/dma-mapping.h:636:21: note: expected ‘dma_addr_t * {aka long long unsigned int *}’ but argument is of type ‘phys_addr_t * {aka unsigned int *}’
>  static inline void *dma_alloc_coherent(struct device *dev, size_t size,
>                      ^~~~~~~~~~~~~~~~~~
> ```
> 
> We just can cast phys_addr_t to dma_addr_t here.

IME, casting is rarely a proper solution.


> diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
> index 2ddc118dba1b..7f6c841fa200 100644
> --- a/drivers/firmware/qcom_scm.c
> +++ b/drivers/firmware/qcom_scm.c
> @@ -457,7 +457,8 @@ int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
>  	ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
>  			ALIGN(dest_sz, SZ_64);
>  
> -	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
> +	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, (dma_addr_t *) &ptr_phys,
> +					GFP_KERNEL);
>  	if (!ptr)
>  		return -ENOMEM;
>
Christoph Hellwig July 22, 2019, 9:30 a.m. UTC | #2
On Mon, Jul 22, 2019 at 10:38:55AM +0200, Marc Gonzalez wrote:
> > In file included from drivers/firmware/qcom_scm.c:12:0:
> > ./include/linux/dma-mapping.h:636:21: note: expected ‘dma_addr_t * {aka long long unsigned int *}’ but argument is of type ‘phys_addr_t * {aka unsigned int *}’
> >  static inline void *dma_alloc_coherent(struct device *dev, size_t size,
> >                      ^~~~~~~~~~~~~~~~~~
> > ```
> > 
> > We just can cast phys_addr_t to dma_addr_t here.
> 
> IME, casting is rarely a proper solution.

*nod*

ptr_phys probably should be a dma_addr_t.  Unless this driver is so
magic that it really wants a physical and not a dma address, in which
case it needs to use alloc_pages instead of dma_alloc_coherent
and then call page_to_phys on the returned page, and a very big comment
explaining why it is so special.
Bjorn Andersson July 22, 2019, 3:12 p.m. UTC | #3
On Mon 22 Jul 02:30 PDT 2019, Christoph Hellwig wrote:

> On Mon, Jul 22, 2019 at 10:38:55AM +0200, Marc Gonzalez wrote:
> > > In file included from drivers/firmware/qcom_scm.c:12:0:
> > > ./include/linux/dma-mapping.h:636:21: note: expected ‘dma_addr_t * {aka long long unsigned int *}’ but argument is of type ‘phys_addr_t * {aka unsigned int *}’
> > >  static inline void *dma_alloc_coherent(struct device *dev, size_t size,
> > >                      ^~~~~~~~~~~~~~~~~~
> > > ```
> > > 
> > > We just can cast phys_addr_t to dma_addr_t here.
> > 
> > IME, casting is rarely a proper solution.
> 
> *nod*
> 
> ptr_phys probably should be a dma_addr_t.  Unless this driver is so
> magic that it really wants a physical and not a dma address, in which
> case it needs to use alloc_pages instead of dma_alloc_coherent
> and then call page_to_phys on the returned page, and a very big comment
> explaining why it is so special.

The scm call takes physical addresses (which happens to be 1:1 with DMA
addresses for this driver).

This allocation started off (downstream) as a simple kmalloc(), but
while the scm call is being executed an access from Linux will cause a
security violation (that's not handled gracefully). The properties of
dma_alloc is closer, so that's where the code is today.

Optimally this should be something like alloc_pages() and some mechanism
for unmapping the pages during the call. But no one has come up with a
suitable patch for that.


But there's a patch from Stephen for this already (not doing a
typecast).  Apparently I missed merging this, so I'll do that.

https://lore.kernel.org/linux-arm-msm/20190517210923.202131-2-swboyd@chromium.org/

Regards,
Bjorn
Minwoo Im July 23, 2019, 1:28 p.m. UTC | #4
> > > > We just can cast phys_addr_t to dma_addr_t here.
> > > 
> > > IME, casting is rarely a proper solution.
> > 
> > *nod*
> > 
> > ptr_phys probably should be a dma_addr_t.  Unless this driver is so
> > magic that it really wants a physical and not a dma address, in which
> > case it needs to use alloc_pages instead of dma_alloc_coherent
> > and then call page_to_phys on the returned page, and a very big comment
> > explaining why it is so special.
> 
> The scm call takes physical addresses (which happens to be 1:1 with DMA
> addresses for this driver).
> 
> This allocation started off (downstream) as a simple kmalloc(), but
> while the scm call is being executed an access from Linux will cause a
> security violation (that's not handled gracefully). The properties of
> dma_alloc is closer, so that's where the code is today.
> 
> Optimally this should be something like alloc_pages() and some mechanism
> for unmapping the pages during the call. But no one has come up with a
> suitable patch for that.
> 
> 
> But there's a patch from Stephen for this already (not doing a
> typecast).  Apparently I missed merging this, so I'll do that.
> 
> https://lore.kernel.org/linux-arm-msm/20190517210923.202131-2-swboyd@chromium.org/

Bjron,

I appreciate for checking this.  And also thanks all you guys for the
comments here!

Thanks,

Patch
diff mbox series

diff --git a/drivers/firmware/qcom_scm.c b/drivers/firmware/qcom_scm.c
index 2ddc118dba1b..7f6c841fa200 100644
--- a/drivers/firmware/qcom_scm.c
+++ b/drivers/firmware/qcom_scm.c
@@ -457,7 +457,8 @@  int qcom_scm_assign_mem(phys_addr_t mem_addr, size_t mem_sz,
 	ptr_sz = ALIGN(src_sz, SZ_64) + ALIGN(mem_to_map_sz, SZ_64) +
 			ALIGN(dest_sz, SZ_64);
 
-	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, &ptr_phys, GFP_KERNEL);
+	ptr = dma_alloc_coherent(__scm->dev, ptr_sz, (dma_addr_t *) &ptr_phys,
+					GFP_KERNEL);
 	if (!ptr)
 		return -ENOMEM;