2019-05-29 17:17:56 +03:00
// SPDX-License-Identifier: GPL-2.0-only
2011-10-20 20:15:13 +04:00
/*
* Remote processor messaging transport ( OMAP platform - specific bits )
*
* Copyright ( C ) 2011 Texas Instruments , Inc .
* Copyright ( C ) 2011 Google , Inc .
*
* Ohad Ben - Cohen < ohad @ wizery . com >
* Brian Swetland < swetland @ google . com >
*/
2022-09-21 16:50:43 +03:00
# include <linux/dma-direct.h>
2020-09-22 16:31:03 +03:00
# include <linux/dma-map-ops.h>
2022-09-21 16:50:43 +03:00
# include <linux/dma-mapping.h>
2011-10-20 20:15:13 +04:00
# include <linux/export.h>
2019-01-10 16:50:49 +03:00
# include <linux/of_reserved_mem.h>
2022-10-05 11:13:17 +03:00
# include <linux/platform_device.h>
2011-10-20 20:15:13 +04:00
# include <linux/remoteproc.h>
# include <linux/virtio.h>
# include <linux/virtio_config.h>
# include <linux/virtio_ids.h>
# include <linux/virtio_ring.h>
# include <linux/err.h>
# include <linux/kref.h>
# include <linux/slab.h>
# include "remoteproc_internal.h"
2022-09-21 16:50:43 +03:00
static int copy_dma_range_map ( struct device * to , struct device * from )
{
const struct bus_dma_region * map = from - > dma_range_map , * new_map , * r ;
int num_ranges = 0 ;
if ( ! map )
return 0 ;
for ( r = map ; r - > size ; r + + )
num_ranges + + ;
new_map = kmemdup ( map , array_size ( num_ranges + 1 , sizeof ( * map ) ) ,
GFP_KERNEL ) ;
if ( ! new_map )
return - ENOMEM ;
to - > dma_range_map = new_map ;
return 0 ;
}
2021-10-01 13:12:30 +03:00
static struct rproc_vdev * vdev_to_rvdev ( struct virtio_device * vdev )
{
2022-09-21 16:50:44 +03:00
struct platform_device * pdev ;
pdev = container_of ( vdev - > dev . parent , struct platform_device , dev ) ;
return platform_get_drvdata ( pdev ) ;
2021-10-01 13:12:30 +03:00
}
static struct rproc * vdev_to_rproc ( struct virtio_device * vdev )
{
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
return rvdev - > rproc ;
}
2011-10-20 20:15:13 +04:00
/* kick the remote processor, and let it know which virtqueue to poke at */
2013-10-29 03:08:50 +04:00
static bool rproc_virtio_notify ( struct virtqueue * vq )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc_vring * rvring = vq - > priv ;
struct rproc * rproc = rvring - > rvdev - > rproc ;
int notifyid = rvring - > notifyid ;
2011-10-20 20:15:13 +04:00
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
dev_dbg ( & rproc - > dev , " kicking vq index: %d \n " , notifyid ) ;
2011-10-20 20:15:13 +04:00
2012-02-14 01:30:39 +04:00
rproc - > ops - > kick ( rproc , notifyid ) ;
2013-10-29 03:08:50 +04:00
return true ;
2011-10-20 20:15:13 +04:00
}
/**
* rproc_vq_interrupt ( ) - tell remoteproc that a virtqueue is interrupted
* @ rproc : handle to the remote processor
2012-02-14 01:30:39 +04:00
* @ notifyid : index of the signalled virtqueue ( unique per this @ rproc )
2011-10-20 20:15:13 +04:00
*
* This function should be called by the platform - specific rproc driver ,
* when the remote processor signals that a specific virtqueue has pending
* messages available .
*
2021-05-19 21:03:04 +03:00
* Return : IRQ_NONE if no message was found in the @ notifyid virtqueue ,
2011-10-20 20:15:13 +04:00
* and otherwise returns IRQ_HANDLED .
*/
2012-02-14 01:30:39 +04:00
irqreturn_t rproc_vq_interrupt ( struct rproc * rproc , int notifyid )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc_vring * rvring ;
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
dev_dbg ( & rproc - > dev , " vq index %d is interrupted \n " , notifyid ) ;
2012-02-14 01:30:39 +04:00
rvring = idr_find ( & rproc - > notifyids , notifyid ) ;
if ( ! rvring | | ! rvring - > vq )
return IRQ_NONE ;
return vring_interrupt ( 0 , rvring - > vq ) ;
2011-10-20 20:15:13 +04:00
}
EXPORT_SYMBOL ( rproc_vq_interrupt ) ;
static struct virtqueue * rp_find_vq ( struct virtio_device * vdev ,
2016-08-13 02:42:19 +03:00
unsigned int id ,
2011-10-20 20:15:13 +04:00
void ( * callback ) ( struct virtqueue * vq ) ,
2017-03-06 19:32:29 +03:00
const char * name , bool ctx )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
2011-10-20 20:15:13 +04:00
struct rproc * rproc = vdev_to_rproc ( vdev ) ;
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
struct device * dev = & rproc - > dev ;
2018-07-27 16:14:47 +03:00
struct rproc_mem_entry * mem ;
2012-02-14 01:30:39 +04:00
struct rproc_vring * rvring ;
2018-07-27 16:14:47 +03:00
struct fw_rsc_vdev * rsc ;
2011-10-20 20:15:13 +04:00
struct virtqueue * vq ;
void * addr ;
2022-06-24 05:55:41 +03:00
int num , size ;
2011-10-20 20:15:13 +04:00
2012-02-14 01:30:39 +04:00
/* we're temporarily limited to two virtqueues per rvdev */
if ( id > = ARRAY_SIZE ( rvdev - > vring ) )
return ERR_PTR ( - EINVAL ) ;
2012-09-05 22:47:45 +04:00
if ( ! name )
return NULL ;
2018-07-27 16:14:47 +03:00
/* Search allocated memory region by name */
mem = rproc_find_carveout_by_name ( rproc , " vdev%dvring%d " , rvdev - > index ,
id ) ;
if ( ! mem | | ! mem - > va )
return ERR_PTR ( - ENOMEM ) ;
2012-05-17 15:23:59 +04:00
rvring = & rvdev - > vring [ id ] ;
2018-07-27 16:14:47 +03:00
addr = mem - > va ;
2022-06-24 05:55:41 +03:00
num = rvring - > num ;
2011-10-20 20:15:13 +04:00
2012-02-14 01:30:39 +04:00
/* zero vring */
2022-06-24 05:55:41 +03:00
size = vring_size ( num , rvring - > align ) ;
2012-02-14 01:30:39 +04:00
memset ( addr , 0 , size ) ;
2011-10-20 20:15:13 +04:00
2018-07-06 15:38:27 +03:00
dev_dbg ( dev , " vring%d: va %pK qsz %d notifyid %d \n " ,
2022-06-24 05:55:41 +03:00
id , addr , num , rvring - > notifyid ) ;
2011-10-20 20:15:13 +04:00
2012-01-12 11:26:57 +04:00
/*
* Create the new vq , and tell virtio we ' re not interested in
* the ' weak ' smp barriers , since we ' re talking with a real device .
*/
2022-06-24 05:55:41 +03:00
vq = vring_new_virtqueue ( id , num , rvring - > align , vdev , false , ctx ,
2017-03-06 19:32:29 +03:00
addr , rproc_virtio_notify , callback , name ) ;
2011-10-20 20:15:13 +04:00
if ( ! vq ) {
remoteproc: maintain a generic child device for each rproc
For each registered rproc, maintain a generic remoteproc device whose
parent is the low level platform-specific device (commonly a pdev, but
it may certainly be any other type of device too).
With this in hand, the resulting device hierarchy might then look like:
omap-rproc.0
|
- remoteproc0 <---- new !
|
- virtio0
|
- virtio1
|
- rpmsg0
|
- rpmsg1
|
- rpmsg2
Where:
- omap-rproc.0 is the low level device that's bound to the
driver which invokes rproc_register()
- remoteproc0 is the result of this patch, and will be added by the
remoteproc framework when rproc_register() is invoked
- virtio0 and virtio1 are vdevs that are registered by remoteproc
when it realizes that they are supported by the firmware
of the physical remote processor represented by omap-rproc.0
- rpmsg0, rpmsg1 and rpmsg2 are rpmsg devices that represent rpmsg
channels, and are registerd by the rpmsg bus when it gets notified
about their existence
Technically, this patch:
- changes 'struct rproc' to contain this generic remoteproc.x device
- creates a new "remoteproc" type, to which this new generic remoteproc.x
device belong to.
- adds a super simple enumeration method for the indices of the
remoteproc.x devices
- updates all dev_* messaging to use the generic remoteproc.x device
instead of the low level platform-specific device
- updates all dma_* allocations to use the parent of remoteproc.x (where
the platform-specific memory pools, most commonly CMA, are to be found)
Adding this generic device has several merits:
- we can now add remoteproc runtime PM support simply by hooking onto the
new "remoteproc" type
- all remoteproc log messages will now carry a common name prefix
instead of having a platform-specific one
- having a device as part of the rproc struct makes it possible to simplify
refcounting (see subsequent patch)
Thanks to Stephen Boyd <sboyd@codeaurora.org> for suggesting and
discussing these ideas in one of the remoteproc review threads and
to Fernando Guzman Lugo <fernando.lugo@ti.com> for trying them out
with the (upcoming) runtime PM support for remoteproc.
Cc: Fernando Guzman Lugo <fernando.lugo@ti.com>
Reviewed-by: Stephen Boyd <sboyd@codeaurora.org>
Signed-off-by: Ohad Ben-Cohen <ohad@wizery.com>
2012-05-30 23:01:25 +04:00
dev_err ( dev , " vring_new_virtqueue %s failed \n " , name ) ;
2012-05-17 15:23:59 +04:00
rproc_free_vring ( rvring ) ;
2012-02-14 01:30:39 +04:00
return ERR_PTR ( - ENOMEM ) ;
2011-10-20 20:15:13 +04:00
}
2022-08-01 09:38:21 +03:00
vq - > num_max = num ;
2012-02-14 01:30:39 +04:00
rvring - > vq = vq ;
vq - > priv = rvring ;
2011-10-20 20:15:13 +04:00
2018-07-27 16:14:47 +03:00
/* Update vring in resource table */
rsc = ( void * ) rproc - > table_ptr + rvdev - > rsc_offset ;
rsc - > vring [ id ] . da = mem - > da ;
2011-10-20 20:15:13 +04:00
return vq ;
}
2012-11-12 13:13:51 +04:00
static void __rproc_virtio_del_vqs ( struct virtio_device * vdev )
2011-10-20 20:15:13 +04:00
{
struct virtqueue * vq , * n ;
2012-02-14 01:30:39 +04:00
struct rproc_vring * rvring ;
2011-10-20 20:15:13 +04:00
list_for_each_entry_safe ( vq , n , & vdev - > vqs , list ) {
2012-02-14 01:30:39 +04:00
rvring = vq - > priv ;
rvring - > vq = NULL ;
2011-10-20 20:15:13 +04:00
vring_del_virtqueue ( vq ) ;
}
}
2012-11-12 13:13:51 +04:00
static void rproc_virtio_del_vqs ( struct virtio_device * vdev )
{
__rproc_virtio_del_vqs ( vdev ) ;
}
2016-08-13 02:42:19 +03:00
static int rproc_virtio_find_vqs ( struct virtio_device * vdev , unsigned int nvqs ,
2016-08-13 02:42:20 +03:00
struct virtqueue * vqs [ ] ,
vq_callback_t * callbacks [ ] ,
2017-02-05 20:15:22 +03:00
const char * const names [ ] ,
2017-03-06 19:32:29 +03:00
const bool * ctx ,
2017-02-05 20:15:22 +03:00
struct irq_affinity * desc )
2011-10-20 20:15:13 +04:00
{
2018-12-28 05:26:26 +03:00
int i , ret , queue_idx = 0 ;
2011-10-20 20:15:13 +04:00
for ( i = 0 ; i < nvqs ; + + i ) {
2018-12-28 05:26:26 +03:00
if ( ! names [ i ] ) {
vqs [ i ] = NULL ;
continue ;
}
vqs [ i ] = rp_find_vq ( vdev , queue_idx + + , callbacks [ i ] , names [ i ] ,
2017-03-06 19:32:29 +03:00
ctx ? ctx [ i ] : false ) ;
2011-10-20 20:15:13 +04:00
if ( IS_ERR ( vqs [ i ] ) ) {
ret = PTR_ERR ( vqs [ i ] ) ;
goto error ;
}
}
return 0 ;
error :
2012-11-12 13:13:51 +04:00
__rproc_virtio_del_vqs ( vdev ) ;
2011-10-20 20:15:13 +04:00
return ret ;
}
static u8 rproc_virtio_get_status ( struct virtio_device * vdev )
{
2013-02-21 21:15:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
struct fw_rsc_vdev * rsc ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
return rsc - > status ;
2011-10-20 20:15:13 +04:00
}
static void rproc_virtio_set_status ( struct virtio_device * vdev , u8 status )
{
2013-02-21 21:15:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
struct fw_rsc_vdev * rsc ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
rsc - > status = status ;
2012-02-14 01:30:39 +04:00
dev_dbg ( & vdev - > dev , " status: %d \n " , status ) ;
2011-10-20 20:15:13 +04:00
}
static void rproc_virtio_reset ( struct virtio_device * vdev )
{
2013-02-21 21:15:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
struct fw_rsc_vdev * rsc ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
rsc - > status = 0 ;
2011-10-20 20:15:13 +04:00
dev_dbg ( & vdev - > dev , " reset ! \n " ) ;
}
/* provide the vdev features as retrieved from the firmware */
2014-10-07 18:39:43 +04:00
static u64 rproc_virtio_get_features ( struct virtio_device * vdev )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
2013-02-21 21:15:39 +04:00
struct fw_rsc_vdev * rsc ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
2011-10-20 20:15:13 +04:00
2013-02-21 21:15:39 +04:00
return rsc - > dfeatures ;
2011-10-20 20:15:13 +04:00
}
2018-11-21 13:03:29 +03:00
static void rproc_transport_features ( struct virtio_device * vdev )
{
/*
* Packed ring isn ' t enabled on remoteproc for now ,
* because remoteproc uses vring_new_virtqueue ( ) which
* creates virtio rings on preallocated memory .
*/
__virtio_clear_bit ( vdev , VIRTIO_F_RING_PACKED ) ;
}
2014-12-04 21:20:27 +03:00
static int rproc_virtio_finalize_features ( struct virtio_device * vdev )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
2013-02-21 21:15:39 +04:00
struct fw_rsc_vdev * rsc ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
2011-10-20 20:15:13 +04:00
/* Give virtio_ring a chance to accept features */
vring_transport_features ( vdev ) ;
2018-11-21 13:03:29 +03:00
/* Give virtio_rproc a chance to accept features. */
rproc_transport_features ( vdev ) ;
2014-11-27 14:45:58 +03:00
/* Make sure we don't have any features > 32 bits! */
BUG_ON ( ( u32 ) vdev - > features ! = vdev - > features ) ;
2011-10-20 20:15:13 +04:00
/*
* Remember the finalized features of our vdev , and provide it
* to the remote processor once it is powered on .
*/
2014-10-07 18:39:42 +04:00
rsc - > gfeatures = vdev - > features ;
2014-12-04 21:20:27 +03:00
return 0 ;
2013-02-21 21:15:39 +04:00
}
2016-08-13 02:42:19 +03:00
static void rproc_virtio_get ( struct virtio_device * vdev , unsigned int offset ,
void * buf , unsigned int len )
2013-02-21 21:15:39 +04:00
{
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
struct fw_rsc_vdev * rsc ;
void * cfg ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
cfg = & rsc - > vring [ rsc - > num_of_vrings ] ;
if ( offset + len > rsc - > config_len | | offset + len < len ) {
dev_err ( & vdev - > dev , " rproc_virtio_get: access out of bounds \n " ) ;
return ;
}
memcpy ( buf , cfg + offset , len ) ;
}
2016-08-13 02:42:19 +03:00
static void rproc_virtio_set ( struct virtio_device * vdev , unsigned int offset ,
const void * buf , unsigned int len )
2013-02-21 21:15:39 +04:00
{
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
struct fw_rsc_vdev * rsc ;
void * cfg ;
rsc = ( void * ) rvdev - > rproc - > table_ptr + rvdev - > rsc_offset ;
cfg = & rsc - > vring [ rsc - > num_of_vrings ] ;
if ( offset + len > rsc - > config_len | | offset + len < len ) {
dev_err ( & vdev - > dev , " rproc_virtio_set: access out of bounds \n " ) ;
return ;
}
memcpy ( cfg + offset , buf , len ) ;
2011-10-20 20:15:13 +04:00
}
2013-02-10 09:27:38 +04:00
static const struct virtio_config_ops rproc_virtio_config_ops = {
2011-10-20 20:15:13 +04:00
. get_features = rproc_virtio_get_features ,
. finalize_features = rproc_virtio_finalize_features ,
. find_vqs = rproc_virtio_find_vqs ,
. del_vqs = rproc_virtio_del_vqs ,
. reset = rproc_virtio_reset ,
. set_status = rproc_virtio_set_status ,
. get_status = rproc_virtio_get_status ,
2013-02-21 21:15:39 +04:00
. get = rproc_virtio_get ,
. set = rproc_virtio_set ,
2011-10-20 20:15:13 +04:00
} ;
/*
* This function is called whenever vdev is released , and is responsible
2012-05-30 23:02:24 +04:00
* to decrement the remote processor ' s refcount which was taken when vdev was
2011-10-20 20:15:13 +04:00
* added .
*
* Never call this function directly ; it will be called by the driver
* core when needed .
*/
2016-10-20 05:40:06 +03:00
static void rproc_virtio_dev_release ( struct device * dev )
2011-10-20 20:15:13 +04:00
{
struct virtio_device * vdev = dev_to_virtio ( dev ) ;
2012-05-17 15:23:59 +04:00
struct rproc_vdev * rvdev = vdev_to_rvdev ( vdev ) ;
2011-10-20 20:15:13 +04:00
2019-01-21 16:55:15 +03:00
kfree ( vdev ) ;
2022-09-21 16:50:44 +03:00
put_device ( & rvdev - > pdev - > dev ) ;
2011-10-20 20:15:13 +04:00
}
/**
2012-02-14 01:30:39 +04:00
* rproc_add_virtio_dev ( ) - register an rproc - induced virtio device
* @ rvdev : the remote vdev
2020-02-12 19:19:56 +03:00
* @ id : the device type identification ( used to match it with a driver ) .
2011-10-20 20:15:13 +04:00
*
2012-02-14 01:30:39 +04:00
* This function registers a virtio device . This vdev ' s partent is
* the rproc device .
2011-10-20 20:15:13 +04:00
*
2021-05-19 21:03:04 +03:00
* Return : 0 on success or an appropriate error value otherwise
2011-10-20 20:15:13 +04:00
*/
2022-09-21 16:50:43 +03:00
static int rproc_add_virtio_dev ( struct rproc_vdev * rvdev , int id )
2011-10-20 20:15:13 +04:00
{
2012-02-14 01:30:39 +04:00
struct rproc * rproc = rvdev - > rproc ;
2022-09-21 16:50:44 +03:00
struct device * dev = & rvdev - > pdev - > dev ;
2019-01-21 16:55:15 +03:00
struct virtio_device * vdev ;
2019-01-10 16:50:49 +03:00
struct rproc_mem_entry * mem ;
2011-10-20 20:15:13 +04:00
int ret ;
2020-03-06 10:24:53 +03:00
if ( rproc - > ops - > kick = = NULL ) {
ret = - EINVAL ;
2020-04-11 19:07:50 +03:00
dev_err ( dev , " .kick method not defined for %s \n " , rproc - > name ) ;
2020-03-06 10:24:53 +03:00
goto out ;
}
2019-01-10 16:50:49 +03:00
/* Try to find dedicated vdev buffer carveout */
mem = rproc_find_carveout_by_name ( rproc , " vdev%dbuffer " , rvdev - > index ) ;
if ( mem ) {
phys_addr_t pa ;
if ( mem - > of_resm_idx ! = - 1 ) {
struct device_node * np = rproc - > dev . parent - > of_node ;
/* Associate reserved memory to vdev device */
ret = of_reserved_mem_device_init_by_idx ( dev , np ,
mem - > of_resm_idx ) ;
if ( ret ) {
dev_err ( dev , " Can't associate reserved memory \n " ) ;
goto out ;
}
} else {
if ( mem - > va ) {
dev_warn ( dev , " vdev %d buffer already mapped \n " ,
rvdev - > index ) ;
pa = rproc_va_to_pa ( mem - > va ) ;
} else {
/* Use dma address as carveout no memmapped yet */
pa = ( phys_addr_t ) mem - > dma ;
}
/* Associate vdev buffer memory pool to vdev subdev */
ret = dma_declare_coherent_memory ( dev , pa ,
mem - > da ,
2019-02-22 08:14:45 +03:00
mem - > len ) ;
2019-01-10 16:50:49 +03:00
if ( ret < 0 ) {
dev_err ( dev , " Failed to associate buffer \n " ) ;
goto out ;
}
}
2020-04-20 19:05:59 +03:00
} else {
struct device_node * np = rproc - > dev . parent - > of_node ;
/*
* If we don ' t have dedicated buffer , just attempt to re - assign
* the reserved memory from our parent . A default memory - region
* at index 0 from the parent ' s memory - regions is assigned for
* the rvdev dev to allocate from . Failure is non - critical and
* the allocations will fall back to global pools , so don ' t
* check return value either .
*/
of_reserved_mem_device_init_by_idx ( dev , np , 0 ) ;
2019-01-10 16:50:49 +03:00
}
2019-01-21 16:55:15 +03:00
/* Allocate virtio device */
vdev = kzalloc ( sizeof ( * vdev ) , GFP_KERNEL ) ;
if ( ! vdev ) {
ret = - ENOMEM ;
goto out ;
}
2012-02-14 01:30:39 +04:00
vdev - > id . device = id ,
vdev - > config = & rproc_virtio_config_ops ,
vdev - > dev . parent = dev ;
2016-10-20 05:40:06 +03:00
vdev - > dev . release = rproc_virtio_dev_release ;
2011-10-20 20:15:13 +04:00
2016-10-20 05:40:06 +03:00
/* Reference the vdev and vring allocations */
2022-09-21 16:50:44 +03:00
get_device ( dev ) ;
2016-10-20 05:40:06 +03:00
2012-02-14 01:30:39 +04:00
ret = register_virtio_device ( vdev ) ;
2011-10-20 20:15:13 +04:00
if ( ret ) {
2017-12-21 15:40:58 +03:00
put_device ( & vdev - > dev ) ;
2011-10-20 20:15:13 +04:00
dev_err ( dev , " failed to register vdev: %d \n " , ret ) ;
2012-02-14 01:30:39 +04:00
goto out ;
2011-10-20 20:15:13 +04:00
}
2012-02-14 01:30:39 +04:00
dev_info ( dev , " registered %s (type %d) \n " , dev_name ( & vdev - > dev ) , id ) ;
out :
2011-10-20 20:15:13 +04:00
return ret ;
}
/**
2012-02-14 01:30:39 +04:00
* rproc_remove_virtio_dev ( ) - remove an rproc - induced virtio device
2019-01-21 16:55:15 +03:00
* @ dev : the virtio device
* @ data : must be null
2011-10-20 20:15:13 +04:00
*
2012-02-14 01:30:39 +04:00
* This function unregisters an existing virtio device .
2021-05-19 21:03:04 +03:00
*
* Return : 0
2011-10-20 20:15:13 +04:00
*/
2022-09-21 16:50:43 +03:00
static int rproc_remove_virtio_dev ( struct device * dev , void * data )
2011-10-20 20:15:13 +04:00
{
2019-01-21 16:55:15 +03:00
struct virtio_device * vdev = dev_to_virtio ( dev ) ;
unregister_virtio_device ( vdev ) ;
return 0 ;
2011-10-20 20:15:13 +04:00
}
2022-09-21 16:50:43 +03:00
static int rproc_vdev_do_start ( struct rproc_subdev * subdev )
{
struct rproc_vdev * rvdev = container_of ( subdev , struct rproc_vdev , subdev ) ;
return rproc_add_virtio_dev ( rvdev , rvdev - > id ) ;
}
static void rproc_vdev_do_stop ( struct rproc_subdev * subdev , bool crashed )
{
struct rproc_vdev * rvdev = container_of ( subdev , struct rproc_vdev , subdev ) ;
2022-09-21 16:50:44 +03:00
struct device * dev = & rvdev - > pdev - > dev ;
2022-09-21 16:50:43 +03:00
int ret ;
2022-09-21 16:50:44 +03:00
ret = device_for_each_child ( dev , NULL , rproc_remove_virtio_dev ) ;
2022-09-21 16:50:43 +03:00
if ( ret )
2022-09-21 16:50:44 +03:00
dev_warn ( dev , " can't remove vdev child device: %d \n " , ret ) ;
2022-09-21 16:50:43 +03:00
}
2022-09-21 16:50:44 +03:00
static int rproc_virtio_probe ( struct platform_device * pdev )
2022-09-21 16:50:43 +03:00
{
2022-09-21 16:50:44 +03:00
struct device * dev = & pdev - > dev ;
struct rproc_vdev_data * rvdev_data = dev - > platform_data ;
2022-09-21 16:50:43 +03:00
struct rproc_vdev * rvdev ;
2022-09-21 16:50:44 +03:00
struct rproc * rproc = container_of ( dev - > parent , struct rproc , dev ) ;
struct fw_rsc_vdev * rsc ;
2022-09-21 16:50:43 +03:00
int i , ret ;
2022-09-21 16:50:44 +03:00
if ( ! rvdev_data )
return - EINVAL ;
2022-09-21 16:50:43 +03:00
2022-09-21 16:50:44 +03:00
rvdev = devm_kzalloc ( dev , sizeof ( * rvdev ) , GFP_KERNEL ) ;
if ( ! rvdev )
return - ENOMEM ;
2022-09-21 16:50:43 +03:00
rvdev - > id = rvdev_data - > id ;
rvdev - > rproc = rproc ;
rvdev - > index = rvdev_data - > index ;
2022-09-21 16:50:44 +03:00
ret = copy_dma_range_map ( dev , rproc - > dev . parent ) ;
2022-09-21 16:50:43 +03:00
if ( ret )
2022-09-21 16:50:44 +03:00
return ret ;
2022-09-21 16:50:43 +03:00
/* Make device dma capable by inheriting from parent's capabilities */
2022-09-21 16:50:44 +03:00
set_dma_ops ( dev , get_dma_ops ( rproc - > dev . parent ) ) ;
2022-09-21 16:50:43 +03:00
2022-09-21 16:50:44 +03:00
ret = dma_coerce_mask_and_coherent ( dev , dma_get_mask ( rproc - > dev . parent ) ) ;
2022-09-21 16:50:43 +03:00
if ( ret ) {
2022-09-21 16:50:44 +03:00
dev_warn ( dev , " Failed to set DMA mask %llx. Trying to continue... (%pe) \n " ,
2022-09-21 16:50:43 +03:00
dma_get_mask ( rproc - > dev . parent ) , ERR_PTR ( ret ) ) ;
}
2022-09-21 16:50:44 +03:00
platform_set_drvdata ( pdev , rvdev ) ;
rvdev - > pdev = pdev ;
rsc = rvdev_data - > rsc ;
2022-09-21 16:50:43 +03:00
/* parse the vrings */
for ( i = 0 ; i < rsc - > num_of_vrings ; i + + ) {
ret = rproc_parse_vring ( rvdev , rsc , i ) ;
if ( ret )
2022-09-21 16:50:44 +03:00
return ret ;
2022-09-21 16:50:43 +03:00
}
/* remember the resource offset*/
rvdev - > rsc_offset = rvdev_data - > rsc_offset ;
/* allocate the vring resources */
for ( i = 0 ; i < rsc - > num_of_vrings ; i + + ) {
ret = rproc_alloc_vring ( rvdev , i ) ;
if ( ret )
goto unwind_vring_allocations ;
}
rproc_add_rvdev ( rproc , rvdev ) ;
rvdev - > subdev . start = rproc_vdev_do_start ;
rvdev - > subdev . stop = rproc_vdev_do_stop ;
rproc_add_subdev ( rproc , & rvdev - > subdev ) ;
2022-09-21 16:50:44 +03:00
/*
* We ' re indirectly making a non - temporary copy of the rproc pointer
* here , because the platform device or the vdev device will indirectly
* access the wrapping rproc .
*
* Therefore we must increment the rproc refcount here , and decrement
* it _only_ on platform remove .
*/
get_device ( & rproc - > dev ) ;
return 0 ;
2022-09-21 16:50:43 +03:00
unwind_vring_allocations :
for ( i - - ; i > = 0 ; i - - )
rproc_free_vring ( & rvdev - > vring [ i ] ) ;
2022-09-21 16:50:44 +03:00
return ret ;
2022-09-21 16:50:43 +03:00
}
2023-05-04 22:44:50 +03:00
static void rproc_virtio_remove ( struct platform_device * pdev )
2022-09-21 16:50:43 +03:00
{
2022-09-21 16:50:44 +03:00
struct rproc_vdev * rvdev = dev_get_drvdata ( & pdev - > dev ) ;
2022-09-21 16:50:43 +03:00
struct rproc * rproc = rvdev - > rproc ;
2022-09-21 16:50:44 +03:00
struct rproc_vring * rvring ;
2022-09-21 16:50:43 +03:00
int id ;
for ( id = 0 ; id < ARRAY_SIZE ( rvdev - > vring ) ; id + + ) {
rvring = & rvdev - > vring [ id ] ;
rproc_free_vring ( rvring ) ;
}
rproc_remove_subdev ( rproc , & rvdev - > subdev ) ;
rproc_remove_rvdev ( rvdev ) ;
2022-09-21 16:50:44 +03:00
of_reserved_mem_device_release ( & pdev - > dev ) ;
dma_release_coherent_memory ( & pdev - > dev ) ;
put_device ( & rproc - > dev ) ;
2022-09-21 16:50:43 +03:00
}
2022-09-21 16:50:44 +03:00
/* Platform driver */
static struct platform_driver rproc_virtio_driver = {
. probe = rproc_virtio_probe ,
2023-05-04 22:44:50 +03:00
. remove_new = rproc_virtio_remove ,
2022-09-21 16:50:44 +03:00
. driver = {
. name = " rproc-virtio " ,
} ,
} ;
builtin_platform_driver ( rproc_virtio_driver ) ;