2018-05-31 20:11:00 +03:00
// SPDX-License-Identifier: GPL-2.0
2011-10-20 23:10:55 +04:00
/*
* Virtio - based remote processor messaging bus
*
* Copyright ( C ) 2011 Texas Instruments , Inc .
* Copyright ( C ) 2011 Google , Inc .
*
* Ohad Ben - Cohen < ohad @ wizery . com >
* Brian Swetland < swetland @ google . com >
*/
# define pr_fmt(fmt) "%s: " fmt, __func__
# include <linux/kernel.h>
# include <linux/module.h>
# include <linux/virtio.h>
# include <linux/virtio_ids.h>
# include <linux/virtio_config.h>
# include <linux/scatterlist.h>
# include <linux/dma-mapping.h>
# include <linux/slab.h>
# include <linux/idr.h>
# include <linux/jiffies.h>
# include <linux/sched.h>
# include <linux/wait.h>
# include <linux/rpmsg.h>
# include <linux/mutex.h>
2016-09-02 01:27:53 +03:00
# include <linux/of_device.h>
2011-10-20 23:10:55 +04:00
2016-09-02 01:28:02 +03:00
# include "rpmsg_internal.h"
2011-10-20 23:10:55 +04:00
/**
* struct virtproc_info - virtual remote processor state
* @ vdev : the virtio device
* @ rvq : rx virtqueue
* @ svq : tx virtqueue
* @ rbufs : kernel address of rx buffers
* @ sbufs : kernel address of tx buffers
2014-09-16 22:33:07 +04:00
* @ num_bufs : total number of buffers for rx and tx
2017-03-28 14:49:43 +03:00
* @ buf_size : size of one rx or tx buffer
2011-10-20 23:10:55 +04:00
* @ last_sbuf : index of last tx buffer used
* @ bufs_dma : dma base addr of the buffers
* @ tx_lock : protects svq , sbufs and sleepers , to allow concurrent senders .
* sending a message might require waking up a dozing remote
* processor , which involves sleeping , hence the mutex .
* @ endpoints : idr of local endpoints , allows fast retrieval
* @ endpoints_lock : lock of the endpoints set
* @ sendq : wait queue of sending contexts waiting for a tx buffers
* @ sleepers : number of senders that are waiting for a tx buffer
* @ ns_ept : the bus ' s name service endpoint
*
* This structure stores the rpmsg state of a given virtio remote processor
* device ( there might be several virtio proc devices for each physical
* remote processor ) .
*/
struct virtproc_info {
struct virtio_device * vdev ;
struct virtqueue * rvq , * svq ;
void * rbufs , * sbufs ;
2014-09-16 22:33:07 +04:00
unsigned int num_bufs ;
2017-03-28 14:49:43 +03:00
unsigned int buf_size ;
2011-10-20 23:10:55 +04:00
int last_sbuf ;
dma_addr_t bufs_dma ;
struct mutex tx_lock ;
struct idr endpoints ;
struct mutex endpoints_lock ;
wait_queue_head_t sendq ;
atomic_t sleepers ;
struct rpmsg_endpoint * ns_ept ;
} ;
2016-09-02 01:28:07 +03:00
/* The feature bitmap for virtio rpmsg */
# define VIRTIO_RPMSG_F_NS 0 /* RP supports name service notifications */
/**
* struct rpmsg_hdr - common header for all rpmsg messages
* @ src : source address
* @ dst : destination address
* @ reserved : reserved for future use
* @ len : length of payload ( in bytes )
* @ flags : message flags
* @ data : @ len bytes of message payload data
*
* Every message sent ( / received ) on the rpmsg bus begins with this header .
*/
struct rpmsg_hdr {
u32 src ;
u32 dst ;
u32 reserved ;
u16 len ;
u16 flags ;
u8 data [ 0 ] ;
} __packed ;
/**
* struct rpmsg_ns_msg - dynamic name service announcement message
* @ name : name of remote service that is published
* @ addr : address of remote service that is published
* @ flags : indicates whether service is created or destroyed
*
* This message is sent across to publish a new service , or announce
* about its removal . When we receive these messages , an appropriate
* rpmsg channel ( i . e device ) is created / destroyed . In turn , the - > probe ( )
* or - > remove ( ) handler of the appropriate rpmsg driver will be invoked
* ( if / as - soon - as one is registered ) .
*/
struct rpmsg_ns_msg {
char name [ RPMSG_NAME_SIZE ] ;
u32 addr ;
u32 flags ;
} __packed ;
/**
* enum rpmsg_ns_flags - dynamic name service announcement flags
*
* @ RPMSG_NS_CREATE : a new remote service was just created
* @ RPMSG_NS_DESTROY : a known remote service was just destroyed
*/
enum rpmsg_ns_flags {
RPMSG_NS_CREATE = 0 ,
RPMSG_NS_DESTROY = 1 ,
} ;
2016-09-02 01:28:06 +03:00
/**
* @ vrp : the remote processor this channel belongs to
*/
struct virtio_rpmsg_channel {
struct rpmsg_device rpdev ;
struct virtproc_info * vrp ;
} ;
# define to_virtio_rpmsg_channel(_rpdev) \
container_of ( _rpdev , struct virtio_rpmsg_channel , rpdev )
2011-10-20 23:10:55 +04:00
/*
2014-09-16 22:33:07 +04:00
* We ' re allocating buffers of 512 bytes each for communications . The
* number of buffers will be computed from the number of buffers supported
* by the vring , upto a maximum of 512 buffers ( 256 in each direction ) .
2011-10-20 23:10:55 +04:00
*
* Each buffer will have 16 bytes for the msg header and 496 bytes for
* the payload .
*
2014-09-16 22:33:07 +04:00
* This will utilize a maximum total space of 256 KB for the buffers .
2011-10-20 23:10:55 +04:00
*
* We might also want to add support for user - provided buffers in time .
* This will allow bigger buffer size flexibility , and can also be used
* to achieve zero - copy messaging .
*
* Note that these numbers are purely a decision of this driver - we
* can change this without changing anything in the firmware of the remote
* processor .
*/
2014-09-16 22:33:07 +04:00
# define MAX_RPMSG_NUM_BUFS (512)
2017-03-28 14:49:43 +03:00
# define MAX_RPMSG_BUF_SIZE (512)
2011-10-20 23:10:55 +04:00
/*
* Local addresses are dynamically allocated on - demand .
* We do not dynamically assign addresses from the low 1024 range ,
* in order to reserve that address range for predefined services .
*/
# define RPMSG_RESERVED_ADDRESSES (1024)
/* Address 53 is reserved for advertising remote services */
# define RPMSG_NS_ADDR (53)
2016-09-02 01:28:00 +03:00
static void virtio_rpmsg_destroy_ept ( struct rpmsg_endpoint * ept ) ;
static int virtio_rpmsg_send ( struct rpmsg_endpoint * ept , void * data , int len ) ;
static int virtio_rpmsg_sendto ( struct rpmsg_endpoint * ept , void * data , int len ,
u32 dst ) ;
static int virtio_rpmsg_send_offchannel ( struct rpmsg_endpoint * ept , u32 src ,
u32 dst , void * data , int len ) ;
static int virtio_rpmsg_trysend ( struct rpmsg_endpoint * ept , void * data , int len ) ;
static int virtio_rpmsg_trysendto ( struct rpmsg_endpoint * ept , void * data ,
int len , u32 dst ) ;
static int virtio_rpmsg_trysend_offchannel ( struct rpmsg_endpoint * ept , u32 src ,
u32 dst , void * data , int len ) ;
2011-10-20 23:10:55 +04:00
2016-09-02 01:28:00 +03:00
static const struct rpmsg_endpoint_ops virtio_endpoint_ops = {
. destroy_ept = virtio_rpmsg_destroy_ept ,
. send = virtio_rpmsg_send ,
. sendto = virtio_rpmsg_sendto ,
. send_offchannel = virtio_rpmsg_send_offchannel ,
. trysend = virtio_rpmsg_trysend ,
. trysendto = virtio_rpmsg_trysendto ,
. trysend_offchannel = virtio_rpmsg_trysend_offchannel ,
} ;
2017-03-28 14:49:44 +03:00
/**
* rpmsg_sg_init - initialize scatterlist according to cpu address location
* @ sg : scatterlist to fill
* @ cpu_addr : virtual address of the buffer
* @ len : buffer length
*
* An internal function filling scatterlist according to virtual address
* location ( in vmalloc or in kernel ) .
*/
static void
rpmsg_sg_init ( struct scatterlist * sg , void * cpu_addr , unsigned int len )
{
if ( is_vmalloc_addr ( cpu_addr ) ) {
sg_init_table ( sg , 1 ) ;
sg_set_page ( sg , vmalloc_to_page ( cpu_addr ) , len ,
offset_in_page ( cpu_addr ) ) ;
} else {
WARN_ON ( ! virt_addr_valid ( cpu_addr ) ) ;
sg_init_one ( sg , cpu_addr , len ) ;
}
}
2012-06-06 11:09:25 +04:00
/**
* __ept_release ( ) - deallocate an rpmsg endpoint
* @ kref : the ept ' s reference count
*
* This function deallocates an ept , and is invoked when its @ kref refcount
* drops to zero .
*
* Never invoke this function directly !
*/
static void __ept_release ( struct kref * kref )
{
struct rpmsg_endpoint * ept = container_of ( kref , struct rpmsg_endpoint ,
refcount ) ;
/*
* At this point no one holds a reference to ept anymore ,
* so we can directly free it
*/
kfree ( ept ) ;
}
2011-10-20 23:10:55 +04:00
/* for more info, see below documentation of rpmsg_create_ept() */
static struct rpmsg_endpoint * __rpmsg_create_ept ( struct virtproc_info * vrp ,
2016-09-02 01:27:57 +03:00
struct rpmsg_device * rpdev ,
2016-08-13 02:42:26 +03:00
rpmsg_rx_cb_t cb ,
void * priv , u32 addr )
2011-10-20 23:10:55 +04:00
{
2013-02-28 05:04:40 +04:00
int id_min , id_max , id ;
2011-10-20 23:10:55 +04:00
struct rpmsg_endpoint * ept ;
struct device * dev = rpdev ? & rpdev - > dev : & vrp - > vdev - > dev ;
ept = kzalloc ( sizeof ( * ept ) , GFP_KERNEL ) ;
2016-08-13 02:42:24 +03:00
if ( ! ept )
2011-10-20 23:10:55 +04:00
return NULL ;
2012-06-06 11:09:25 +04:00
kref_init ( & ept - > refcount ) ;
2012-06-07 16:39:35 +04:00
mutex_init ( & ept - > cb_lock ) ;
2012-06-06 11:09:25 +04:00
2011-10-20 23:10:55 +04:00
ept - > rpdev = rpdev ;
ept - > cb = cb ;
ept - > priv = priv ;
2016-09-02 01:28:00 +03:00
ept - > ops = & virtio_endpoint_ops ;
2011-10-20 23:10:55 +04:00
/* do we need to allocate a local address ? */
2013-02-28 05:04:40 +04:00
if ( addr = = RPMSG_ADDR_ANY ) {
id_min = RPMSG_RESERVED_ADDRESSES ;
id_max = 0 ;
} else {
id_min = addr ;
id_max = addr + 1 ;
}
2011-10-20 23:10:55 +04:00
mutex_lock ( & vrp - > endpoints_lock ) ;
/* bind the endpoint to an rpmsg address (and allocate one if needed) */
2013-02-28 05:04:40 +04:00
id = idr_alloc ( & vrp - > endpoints , ept , id_min , id_max , GFP_KERNEL ) ;
if ( id < 0 ) {
dev_err ( dev , " idr_alloc failed: %d \n " , id ) ;
2011-10-20 23:10:55 +04:00
goto free_ept ;
}
2013-02-28 05:04:40 +04:00
ept - > addr = id ;
2011-10-20 23:10:55 +04:00
mutex_unlock ( & vrp - > endpoints_lock ) ;
return ept ;
free_ept :
mutex_unlock ( & vrp - > endpoints_lock ) ;
2012-06-06 11:09:25 +04:00
kref_put ( & ept - > refcount , __ept_release ) ;
2011-10-20 23:10:55 +04:00
return NULL ;
}
2016-09-02 01:27:58 +03:00
static struct rpmsg_endpoint * virtio_rpmsg_create_ept ( struct rpmsg_device * rpdev ,
rpmsg_rx_cb_t cb ,
void * priv ,
struct rpmsg_channel_info chinfo )
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( rpdev ) ;
return __rpmsg_create_ept ( vch - > vrp , rpdev , cb , priv , chinfo . src ) ;
2016-09-02 01:27:58 +03:00
}
2011-10-20 23:10:55 +04:00
/**
2012-02-09 17:16:41 +04:00
* __rpmsg_destroy_ept ( ) - destroy an existing rpmsg endpoint
* @ vrp : virtproc which owns this ept
2011-10-20 23:10:55 +04:00
* @ ept : endpoing to destroy
*
2012-02-09 17:16:41 +04:00
* An internal function which destroy an ept without assuming it is
* bound to an rpmsg channel . This is needed for handling the internal
* name service endpoint , which isn ' t bound to an rpmsg channel .
* See also __rpmsg_create_ept ( ) .
2011-10-20 23:10:55 +04:00
*/
2012-02-09 17:16:41 +04:00
static void
__rpmsg_destroy_ept ( struct virtproc_info * vrp , struct rpmsg_endpoint * ept )
2011-10-20 23:10:55 +04:00
{
2012-06-07 16:39:35 +04:00
/* make sure new inbound messages can't find this ept anymore */
2011-10-20 23:10:55 +04:00
mutex_lock ( & vrp - > endpoints_lock ) ;
idr_remove ( & vrp - > endpoints , ept - > addr ) ;
mutex_unlock ( & vrp - > endpoints_lock ) ;
2012-06-07 16:39:35 +04:00
/* make sure in-flight inbound messages won't invoke cb anymore */
mutex_lock ( & ept - > cb_lock ) ;
ept - > cb = NULL ;
mutex_unlock ( & ept - > cb_lock ) ;
2012-06-06 11:09:25 +04:00
kref_put ( & ept - > refcount , __ept_release ) ;
2011-10-20 23:10:55 +04:00
}
2012-02-09 17:16:41 +04:00
2016-09-02 01:28:00 +03:00
static void virtio_rpmsg_destroy_ept ( struct rpmsg_endpoint * ept )
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( ept - > rpdev ) ;
__rpmsg_destroy_ept ( vch - > vrp , ept ) ;
2016-09-02 01:28:00 +03:00
}
2016-09-02 01:27:58 +03:00
static int virtio_rpmsg_announce_create ( struct rpmsg_device * rpdev )
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( rpdev ) ;
struct virtproc_info * vrp = vch - > vrp ;
2016-09-02 01:27:58 +03:00
struct device * dev = & rpdev - > dev ;
int err = 0 ;
2011-10-20 23:10:55 +04:00
/* need to tell remote processor's name service about this channel ? */
2017-06-02 14:35:51 +03:00
if ( rpdev - > announce & & rpdev - > ept & &
2016-08-13 02:42:26 +03:00
virtio_has_feature ( vrp - > vdev , VIRTIO_RPMSG_F_NS ) ) {
2011-10-20 23:10:55 +04:00
struct rpmsg_ns_msg nsm ;
strncpy ( nsm . name , rpdev - > id . name , RPMSG_NAME_SIZE ) ;
2016-09-02 01:27:55 +03:00
nsm . addr = rpdev - > ept - > addr ;
2011-10-20 23:10:55 +04:00
nsm . flags = RPMSG_NS_CREATE ;
2016-09-02 01:27:55 +03:00
err = rpmsg_sendto ( rpdev - > ept , & nsm , sizeof ( nsm ) , RPMSG_NS_ADDR ) ;
2011-10-20 23:10:55 +04:00
if ( err )
dev_err ( dev , " failed to announce service %d \n " , err ) ;
}
return err ;
}
2016-09-02 01:27:58 +03:00
static int virtio_rpmsg_announce_destroy ( struct rpmsg_device * rpdev )
2011-10-20 23:10:55 +04:00
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( rpdev ) ;
struct virtproc_info * vrp = vch - > vrp ;
2016-09-02 01:27:58 +03:00
struct device * dev = & rpdev - > dev ;
2011-10-20 23:10:55 +04:00
int err = 0 ;
/* tell remote processor's name service we're removing this channel */
2017-06-02 14:35:51 +03:00
if ( rpdev - > announce & & rpdev - > ept & &
2016-08-13 02:42:26 +03:00
virtio_has_feature ( vrp - > vdev , VIRTIO_RPMSG_F_NS ) ) {
2011-10-20 23:10:55 +04:00
struct rpmsg_ns_msg nsm ;
strncpy ( nsm . name , rpdev - > id . name , RPMSG_NAME_SIZE ) ;
2017-06-02 14:36:42 +03:00
nsm . addr = rpdev - > ept - > addr ;
2011-10-20 23:10:55 +04:00
nsm . flags = RPMSG_NS_DESTROY ;
2016-09-02 01:27:55 +03:00
err = rpmsg_sendto ( rpdev - > ept , & nsm , sizeof ( nsm ) , RPMSG_NS_ADDR ) ;
2011-10-20 23:10:55 +04:00
if ( err )
dev_err ( dev , " failed to announce service %d \n " , err ) ;
}
2016-09-02 01:27:58 +03:00
return err ;
}
static const struct rpmsg_device_ops virtio_rpmsg_ops = {
. create_ept = virtio_rpmsg_create_ept ,
. announce_create = virtio_rpmsg_announce_create ,
. announce_destroy = virtio_rpmsg_announce_destroy ,
} ;
2017-03-16 08:18:35 +03:00
static void virtio_rpmsg_release_device ( struct device * dev )
{
struct rpmsg_device * rpdev = to_rpmsg_device ( dev ) ;
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( rpdev ) ;
kfree ( vch ) ;
}
2011-10-20 23:10:55 +04:00
/*
* create an rpmsg channel using its name and address info .
* this function will be used to create both static and dynamic
* channels .
*/
2016-09-02 01:27:57 +03:00
static struct rpmsg_device * rpmsg_create_channel ( struct virtproc_info * vrp ,
struct rpmsg_channel_info * chinfo )
2011-10-20 23:10:55 +04:00
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch ;
2016-09-02 01:27:57 +03:00
struct rpmsg_device * rpdev ;
2011-10-20 23:10:55 +04:00
struct device * tmp , * dev = & vrp - > vdev - > dev ;
int ret ;
/* make sure a similar channel doesn't already exist */
2016-09-02 01:28:02 +03:00
tmp = rpmsg_find_device ( dev , chinfo ) ;
2011-10-20 23:10:55 +04:00
if ( tmp ) {
/* decrement the matched device's refcount back */
put_device ( tmp ) ;
dev_err ( dev , " channel %s:%x:%x already exist \n " ,
chinfo - > name , chinfo - > src , chinfo - > dst ) ;
return NULL ;
}
2016-09-02 01:28:06 +03:00
vch = kzalloc ( sizeof ( * vch ) , GFP_KERNEL ) ;
if ( ! vch )
2011-10-20 23:10:55 +04:00
return NULL ;
2016-09-02 01:28:06 +03:00
/* Link the channel to our vrp */
vch - > vrp = vrp ;
/* Assign public information to the rpmsg_device */
rpdev = & vch - > rpdev ;
2011-10-20 23:10:55 +04:00
rpdev - > src = chinfo - > src ;
rpdev - > dst = chinfo - > dst ;
2016-09-02 01:27:58 +03:00
rpdev - > ops = & virtio_rpmsg_ops ;
2011-10-20 23:10:55 +04:00
/*
* rpmsg server channels has predefined local address ( for now ) ,
* and their existence needs to be announced remotely
*/
2016-07-01 17:24:58 +03:00
rpdev - > announce = rpdev - > src ! = RPMSG_ADDR_ANY ;
2011-10-20 23:10:55 +04:00
strncpy ( rpdev - > id . name , chinfo - > name , RPMSG_NAME_SIZE ) ;
2016-09-02 01:28:03 +03:00
rpdev - > dev . parent = & vrp - > vdev - > dev ;
2017-03-16 08:18:35 +03:00
rpdev - > dev . release = virtio_rpmsg_release_device ;
2016-09-02 01:28:03 +03:00
ret = rpmsg_register_device ( rpdev ) ;
if ( ret )
return NULL ;
return rpdev ;
}
2011-10-20 23:10:55 +04:00
/* super simple buffer "allocator" that is just enough for now */
static void * get_a_tx_buf ( struct virtproc_info * vrp )
{
unsigned int len ;
void * ret ;
/* support multiple concurrent senders */
mutex_lock ( & vrp - > tx_lock ) ;
/*
* either pick the next unused tx buffer
* ( half of our buffers are used for sending messages )
*/
2014-09-16 22:33:07 +04:00
if ( vrp - > last_sbuf < vrp - > num_bufs / 2 )
2017-03-28 14:49:43 +03:00
ret = vrp - > sbufs + vrp - > buf_size * vrp - > last_sbuf + + ;
2011-10-20 23:10:55 +04:00
/* or recycle a used one */
else
ret = virtqueue_get_buf ( vrp - > svq , & len ) ;
mutex_unlock ( & vrp - > tx_lock ) ;
return ret ;
}
/**
* rpmsg_upref_sleepers ( ) - enable " tx-complete " interrupts , if needed
* @ vrp : virtual remote processor state
*
* This function is called before a sender is blocked , waiting for
* a tx buffer to become available .
*
* If we already have blocking senders , this function merely increases
* the " sleepers " reference count , and exits .
*
* Otherwise , if this is the first sender to block , we also enable
* virtio ' s tx callbacks , so we ' d be immediately notified when a tx
* buffer is consumed ( we rely on virtio ' s tx callback in order
* to wake up sleeping senders as soon as a tx buffer is used by the
* remote processor ) .
*/
static void rpmsg_upref_sleepers ( struct virtproc_info * vrp )
{
/* support multiple concurrent senders */
mutex_lock ( & vrp - > tx_lock ) ;
/* are we the first sleeping context waiting for tx buffers ? */
if ( atomic_inc_return ( & vrp - > sleepers ) = = 1 )
/* enable "tx-complete" interrupts before dozing off */
virtqueue_enable_cb ( vrp - > svq ) ;
mutex_unlock ( & vrp - > tx_lock ) ;
}
/**
* rpmsg_downref_sleepers ( ) - disable " tx-complete " interrupts , if needed
* @ vrp : virtual remote processor state
*
* This function is called after a sender , that waited for a tx buffer
* to become available , is unblocked .
*
* If we still have blocking senders , this function merely decreases
* the " sleepers " reference count , and exits .
*
* Otherwise , if there are no more blocking senders , we also disable
* virtio ' s tx callbacks , to avoid the overhead incurred with handling
* those ( now redundant ) interrupts .
*/
static void rpmsg_downref_sleepers ( struct virtproc_info * vrp )
{
/* support multiple concurrent senders */
mutex_lock ( & vrp - > tx_lock ) ;
/* are we the last sleeping context waiting for tx buffers ? */
if ( atomic_dec_and_test ( & vrp - > sleepers ) )
/* disable "tx-complete" interrupts */
virtqueue_disable_cb ( vrp - > svq ) ;
mutex_unlock ( & vrp - > tx_lock ) ;
}
/**
* rpmsg_send_offchannel_raw ( ) - send a message across to the remote processor
* @ rpdev : the rpmsg channel
* @ src : source address
* @ dst : destination address
* @ data : payload of message
* @ len : length of payload
* @ wait : indicates whether caller should block in case no TX buffers available
*
* This function is the base implementation for all of the rpmsg sending API .
*
* It will send @ data of length @ len to @ dst , and say it ' s from @ src . The
* message will be sent to the remote processor which the @ rpdev channel
* belongs to .
*
* The message is sent using one of the TX buffers that are available for
* communication with this remote processor .
*
* If @ wait is true , the caller will be blocked until either a TX buffer is
* available , or 15 seconds elapses ( we don ' t want callers to
* sleep indefinitely due to misbehaving remote processors ) , and in that
* case - ERESTARTSYS is returned . The number ' 15 ' itself was picked
* arbitrarily ; there ' s little point in asking drivers to provide a timeout
* value themselves .
*
* Otherwise , if @ wait is false , and there are no TX buffers available ,
* the function will immediately fail , and - ENOMEM will be returned .
*
* Normally drivers shouldn ' t use this function directly ; instead , drivers
* should use the appropriate rpmsg_ { try } send { to , _offchannel } API
* ( see include / linux / rpmsg . h ) .
*
* Returns 0 on success and an appropriate error value on failure .
*/
2016-09-02 01:28:00 +03:00
static int rpmsg_send_offchannel_raw ( struct rpmsg_device * rpdev ,
u32 src , u32 dst ,
void * data , int len , bool wait )
2011-10-20 23:10:55 +04:00
{
2016-09-02 01:28:06 +03:00
struct virtio_rpmsg_channel * vch = to_virtio_rpmsg_channel ( rpdev ) ;
struct virtproc_info * vrp = vch - > vrp ;
2011-10-20 23:10:55 +04:00
struct device * dev = & rpdev - > dev ;
struct scatterlist sg ;
struct rpmsg_hdr * msg ;
int err ;
/* bcasting isn't allowed */
if ( src = = RPMSG_ADDR_ANY | | dst = = RPMSG_ADDR_ANY ) {
dev_err ( dev , " invalid addr (src 0x%x, dst 0x%x) \n " , src , dst ) ;
return - EINVAL ;
}
/*
* We currently use fixed - sized buffers , and therefore the payload
* length is limited .
*
* One of the possible improvements here is either to support
* user - provided buffers ( and then we can also support zero - copy
* messaging ) , or to improve the buffer allocator , to support
* variable - length buffer sizes .
*/
2017-03-28 14:49:43 +03:00
if ( len > vrp - > buf_size - sizeof ( struct rpmsg_hdr ) ) {
2011-10-20 23:10:55 +04:00
dev_err ( dev , " message is too big (%d) \n " , len ) ;
return - EMSGSIZE ;
}
/* grab a buffer */
msg = get_a_tx_buf ( vrp ) ;
if ( ! msg & & ! wait )
return - ENOMEM ;
/* no free buffer ? wait for one (but bail after 15 seconds) */
while ( ! msg ) {
/* enable "tx-complete" interrupts, if not already enabled */
rpmsg_upref_sleepers ( vrp ) ;
/*
* sleep until a free buffer is available or 15 secs elapse .
* the timeout period is not configurable because there ' s
* little point in asking drivers to specify that .
* if later this happens to be required , it ' d be easy to add .
*/
err = wait_event_interruptible_timeout ( vrp - > sendq ,
( msg = get_a_tx_buf ( vrp ) ) ,
msecs_to_jiffies ( 15000 ) ) ;
/* disable "tx-complete" interrupts if we're the last sleeper */
rpmsg_downref_sleepers ( vrp ) ;
/* timeout ? */
if ( ! err ) {
dev_err ( dev , " timeout waiting for a tx buffer \n " ) ;
return - ERESTARTSYS ;
}
}
msg - > len = len ;
msg - > flags = 0 ;
msg - > src = src ;
msg - > dst = dst ;
msg - > reserved = 0 ;
memcpy ( msg - > data , data , len ) ;
dev_dbg ( dev , " TX From 0x%x, To 0x%x, Len %d, Flags %d, Reserved %d \n " ,
2016-08-13 02:42:26 +03:00
msg - > src , msg - > dst , msg - > len , msg - > flags , msg - > reserved ) ;
2016-08-13 02:42:27 +03:00
# if defined(CONFIG_DYNAMIC_DEBUG)
dynamic_hex_dump ( " rpmsg_virtio TX: " , DUMP_PREFIX_NONE , 16 , 1 ,
msg , sizeof ( * msg ) + msg - > len , true ) ;
# endif
2011-10-20 23:10:55 +04:00
2017-03-28 14:49:44 +03:00
rpmsg_sg_init ( & sg , msg , sizeof ( * msg ) + len ) ;
2011-10-20 23:10:55 +04:00
mutex_lock ( & vrp - > tx_lock ) ;
/* add message to the remote processor's virtqueue */
2013-03-20 09:14:29 +04:00
err = virtqueue_add_outbuf ( vrp - > svq , & sg , 1 , msg , GFP_KERNEL ) ;
2012-10-16 17:26:15 +04:00
if ( err ) {
2011-10-20 23:10:55 +04:00
/*
* need to reclaim the buffer here , otherwise it ' s lost
* ( memory won ' t leak , but rpmsg won ' t use it again for TX ) .
* this will wait for a buffer management overhaul .
*/
2013-03-20 09:14:29 +04:00
dev_err ( dev , " virtqueue_add_outbuf failed: %d \n " , err ) ;
2011-10-20 23:10:55 +04:00
goto out ;
}
/* tell the remote processor it has a pending message to read */
virtqueue_kick ( vrp - > svq ) ;
out :
mutex_unlock ( & vrp - > tx_lock ) ;
return err ;
}
2016-09-02 01:28:00 +03:00
static int virtio_rpmsg_send ( struct rpmsg_endpoint * ept , void * data , int len )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
u32 src = ept - > addr , dst = rpdev - > dst ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , true ) ;
}
static int virtio_rpmsg_sendto ( struct rpmsg_endpoint * ept , void * data , int len ,
u32 dst )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
u32 src = ept - > addr ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , true ) ;
}
static int virtio_rpmsg_send_offchannel ( struct rpmsg_endpoint * ept , u32 src ,
u32 dst , void * data , int len )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , true ) ;
}
static int virtio_rpmsg_trysend ( struct rpmsg_endpoint * ept , void * data , int len )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
u32 src = ept - > addr , dst = rpdev - > dst ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , false ) ;
}
static int virtio_rpmsg_trysendto ( struct rpmsg_endpoint * ept , void * data ,
int len , u32 dst )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
u32 src = ept - > addr ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , false ) ;
}
static int virtio_rpmsg_trysend_offchannel ( struct rpmsg_endpoint * ept , u32 src ,
u32 dst , void * data , int len )
{
struct rpmsg_device * rpdev = ept - > rpdev ;
return rpmsg_send_offchannel_raw ( rpdev , src , dst , data , len , false ) ;
}
2013-04-05 18:38:52 +04:00
static int rpmsg_recv_single ( struct virtproc_info * vrp , struct device * dev ,
struct rpmsg_hdr * msg , unsigned int len )
2011-10-20 23:10:55 +04:00
{
struct rpmsg_endpoint * ept ;
struct scatterlist sg ;
int err ;
dev_dbg ( dev , " From: 0x%x, To: 0x%x, Len: %d, Flags: %d, Reserved: %d \n " ,
2016-08-13 02:42:26 +03:00
msg - > src , msg - > dst , msg - > len , msg - > flags , msg - > reserved ) ;
2016-08-13 02:42:27 +03:00
# if defined(CONFIG_DYNAMIC_DEBUG)
dynamic_hex_dump ( " rpmsg_virtio RX: " , DUMP_PREFIX_NONE , 16 , 1 ,
msg , sizeof ( * msg ) + msg - > len , true ) ;
# endif
2011-10-20 23:10:55 +04:00
2012-02-28 18:16:48 +04:00
/*
* We currently use fixed - sized buffers , so trivially sanitize
* the reported payload length .
*/
2017-03-28 14:49:43 +03:00
if ( len > vrp - > buf_size | |
2016-08-13 02:42:26 +03:00
msg - > len > ( len - sizeof ( struct rpmsg_hdr ) ) ) {
2012-02-28 18:16:48 +04:00
dev_warn ( dev , " inbound msg too big: (%d, %d) \n " , len , msg - > len ) ;
2013-04-05 18:38:52 +04:00
return - EINVAL ;
2012-02-28 18:16:48 +04:00
}
2011-10-20 23:10:55 +04:00
/* use the dst addr to fetch the callback of the appropriate user */
mutex_lock ( & vrp - > endpoints_lock ) ;
2012-06-06 11:09:25 +04:00
2011-10-20 23:10:55 +04:00
ept = idr_find ( & vrp - > endpoints , msg - > dst ) ;
2012-06-06 11:09:25 +04:00
/* let's make sure no one deallocates ept while we use it */
if ( ept )
kref_get ( & ept - > refcount ) ;
2011-10-20 23:10:55 +04:00
mutex_unlock ( & vrp - > endpoints_lock ) ;
2012-06-07 16:39:35 +04:00
if ( ept ) {
/* make sure ept->cb doesn't go away while we use it */
mutex_lock ( & ept - > cb_lock ) ;
2011-10-20 23:10:55 +04:00
2012-06-07 16:39:35 +04:00
if ( ept - > cb )
ept - > cb ( ept - > rpdev , msg - > data , msg - > len , ept - > priv ,
msg - > src ) ;
mutex_unlock ( & ept - > cb_lock ) ;
/* farewell, ept, we don't need you anymore */
2012-06-06 11:09:25 +04:00
kref_put ( & ept - > refcount , __ept_release ) ;
2012-06-07 16:39:35 +04:00
} else
2012-12-28 21:00:09 +04:00
dev_warn ( dev , " msg received with no recipient \n " ) ;
2012-06-06 11:09:25 +04:00
2012-02-28 18:11:28 +04:00
/* publish the real size of the buffer */
2017-03-28 14:49:44 +03:00
rpmsg_sg_init ( & sg , msg , vrp - > buf_size ) ;
2011-10-20 23:10:55 +04:00
/* add the buffer back to the remote processor's virtqueue */
2013-03-20 09:14:29 +04:00
err = virtqueue_add_inbuf ( vrp - > rvq , & sg , 1 , msg , GFP_KERNEL ) ;
2011-10-20 23:10:55 +04:00
if ( err < 0 ) {
dev_err ( dev , " failed to add a virtqueue buffer: %d \n " , err ) ;
2013-04-05 18:38:52 +04:00
return err ;
}
return 0 ;
}
/* called when an rx buffer is used, and it's time to digest a message */
static void rpmsg_recv_done ( struct virtqueue * rvq )
{
struct virtproc_info * vrp = rvq - > vdev - > priv ;
struct device * dev = & rvq - > vdev - > dev ;
struct rpmsg_hdr * msg ;
unsigned int len , msgs_received = 0 ;
int err ;
msg = virtqueue_get_buf ( rvq , & len ) ;
if ( ! msg ) {
dev_err ( dev , " uhm, incoming signal, but no used buffer ? \n " ) ;
2011-10-20 23:10:55 +04:00
return ;
}
2013-04-05 18:38:52 +04:00
while ( msg ) {
err = rpmsg_recv_single ( vrp , dev , msg , len ) ;
if ( err )
break ;
msgs_received + + ;
msg = virtqueue_get_buf ( rvq , & len ) ;
2016-07-20 12:29:35 +03:00
}
2013-04-05 18:38:52 +04:00
dev_dbg ( dev , " Received %u messages \n " , msgs_received ) ;
2011-10-20 23:10:55 +04:00
/* tell the remote processor we added another available rx buffer */
2013-04-05 18:38:52 +04:00
if ( msgs_received )
virtqueue_kick ( vrp - > rvq ) ;
2011-10-20 23:10:55 +04:00
}
/*
* This is invoked whenever the remote processor completed processing
* a TX msg we just sent it , and the buffer is put back to the used ring .
*
* Normally , though , we suppress this " tx complete " interrupt in order to
* avoid the incurred overhead .
*/
static void rpmsg_xmit_done ( struct virtqueue * svq )
{
struct virtproc_info * vrp = svq - > vdev - > priv ;
dev_dbg ( & svq - > vdev - > dev , " %s \n " , __func__ ) ;
/* wake up potential senders that are waiting for a tx buffer */
wake_up_interruptible ( & vrp - > sendq ) ;
}
/* invoked when a name service announcement arrives */
2016-09-02 01:28:08 +03:00
static int rpmsg_ns_cb ( struct rpmsg_device * rpdev , void * data , int len ,
void * priv , u32 src )
2011-10-20 23:10:55 +04:00
{
struct rpmsg_ns_msg * msg = data ;
2016-09-02 01:27:57 +03:00
struct rpmsg_device * newch ;
2011-10-20 23:10:55 +04:00
struct rpmsg_channel_info chinfo ;
struct virtproc_info * vrp = priv ;
struct device * dev = & vrp - > vdev - > dev ;
int ret ;
2016-08-13 02:42:27 +03:00
# if defined(CONFIG_DYNAMIC_DEBUG)
dynamic_hex_dump ( " NS announcement: " , DUMP_PREFIX_NONE , 16 , 1 ,
data , len , true ) ;
# endif
2011-10-20 23:10:55 +04:00
if ( len ! = sizeof ( * msg ) ) {
dev_err ( dev , " malformed ns msg (%d) \n " , len ) ;
2016-09-02 01:28:08 +03:00
return - EINVAL ;
2011-10-20 23:10:55 +04:00
}
/*
* the name service ept does _not_ belong to a real rpmsg channel ,
* and is handled by the rpmsg bus itself .
* for sanity reasons , make sure a valid rpdev has _not_ sneaked
* in somehow .
*/
if ( rpdev ) {
dev_err ( dev , " anomaly: ns ept has an rpdev handle \n " ) ;
2016-09-02 01:28:08 +03:00
return - EINVAL ;
2011-10-20 23:10:55 +04:00
}
/* don't trust the remote processor for null terminating the name */
msg - > name [ RPMSG_NAME_SIZE - 1 ] = ' \0 ' ;
dev_info ( dev , " %sing channel %s addr 0x%x \n " ,
2016-08-13 02:42:26 +03:00
msg - > flags & RPMSG_NS_DESTROY ? " destroy " : " creat " ,
msg - > name , msg - > addr ) ;
2011-10-20 23:10:55 +04:00
strncpy ( chinfo . name , msg - > name , sizeof ( chinfo . name ) ) ;
chinfo . src = RPMSG_ADDR_ANY ;
chinfo . dst = msg - > addr ;
if ( msg - > flags & RPMSG_NS_DESTROY ) {
2016-09-02 01:28:04 +03:00
ret = rpmsg_unregister_device ( & vrp - > vdev - > dev , & chinfo ) ;
2011-10-20 23:10:55 +04:00
if ( ret )
dev_err ( dev , " rpmsg_destroy_channel failed: %d \n " , ret ) ;
} else {
newch = rpmsg_create_channel ( vrp , & chinfo ) ;
if ( ! newch )
dev_err ( dev , " rpmsg_create_channel failed \n " ) ;
}
2016-09-02 01:28:08 +03:00
return 0 ;
2011-10-20 23:10:55 +04:00
}
static int rpmsg_probe ( struct virtio_device * vdev )
{
vq_callback_t * vq_cbs [ ] = { rpmsg_recv_done , rpmsg_xmit_done } ;
2015-12-17 11:53:43 +03:00
static const char * const names [ ] = { " input " , " output " } ;
2011-10-20 23:10:55 +04:00
struct virtqueue * vqs [ 2 ] ;
struct virtproc_info * vrp ;
void * bufs_va ;
int err = 0 , i ;
2014-09-16 22:33:07 +04:00
size_t total_buf_space ;
2015-03-12 04:24:41 +03:00
bool notify ;
2011-10-20 23:10:55 +04:00
vrp = kzalloc ( sizeof ( * vrp ) , GFP_KERNEL ) ;
if ( ! vrp )
return - ENOMEM ;
vrp - > vdev = vdev ;
idr_init ( & vrp - > endpoints ) ;
mutex_init ( & vrp - > endpoints_lock ) ;
mutex_init ( & vrp - > tx_lock ) ;
init_waitqueue_head ( & vrp - > sendq ) ;
/* We expect two virtqueues, rx and tx (and in this order) */
2017-03-06 19:19:39 +03:00
err = virtio_find_vqs ( vdev , 2 , vqs , vq_cbs , names , NULL ) ;
2011-10-20 23:10:55 +04:00
if ( err )
goto free_vrp ;
vrp - > rvq = vqs [ 0 ] ;
vrp - > svq = vqs [ 1 ] ;
2014-09-16 22:33:07 +04:00
/* we expect symmetric tx/rx vrings */
WARN_ON ( virtqueue_get_vring_size ( vrp - > rvq ) ! =
virtqueue_get_vring_size ( vrp - > svq ) ) ;
/* we need less buffers if vrings are small */
if ( virtqueue_get_vring_size ( vrp - > rvq ) < MAX_RPMSG_NUM_BUFS / 2 )
vrp - > num_bufs = virtqueue_get_vring_size ( vrp - > rvq ) * 2 ;
else
vrp - > num_bufs = MAX_RPMSG_NUM_BUFS ;
2017-03-28 14:49:43 +03:00
vrp - > buf_size = MAX_RPMSG_BUF_SIZE ;
total_buf_space = vrp - > num_bufs * vrp - > buf_size ;
2014-09-16 22:33:07 +04:00
2011-10-20 23:10:55 +04:00
/* allocate coherent memory for the buffers */
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
bufs_va = dma_alloc_coherent ( vdev - > dev . parent - > parent ,
2014-09-16 22:33:07 +04:00
total_buf_space , & vrp - > bufs_dma ,
GFP_KERNEL ) ;
2013-04-30 03:17:09 +04:00
if ( ! bufs_va ) {
err = - ENOMEM ;
2011-10-20 23:10:55 +04:00
goto vqs_del ;
2013-04-30 03:17:09 +04:00
}
2011-10-20 23:10:55 +04:00
2016-08-13 02:42:25 +03:00
dev_dbg ( & vdev - > dev , " buffers: va %p, dma %pad \n " ,
bufs_va , & vrp - > bufs_dma ) ;
2011-10-20 23:10:55 +04:00
/* half of the buffers is dedicated for RX */
vrp - > rbufs = bufs_va ;
/* and half is dedicated for TX */
2014-09-16 22:33:07 +04:00
vrp - > sbufs = bufs_va + total_buf_space / 2 ;
2011-10-20 23:10:55 +04:00
/* set up the receive buffers */
2014-09-16 22:33:07 +04:00
for ( i = 0 ; i < vrp - > num_bufs / 2 ; i + + ) {
2011-10-20 23:10:55 +04:00
struct scatterlist sg ;
2017-03-28 14:49:43 +03:00
void * cpu_addr = vrp - > rbufs + i * vrp - > buf_size ;
2011-10-20 23:10:55 +04:00
2017-03-28 14:49:44 +03:00
rpmsg_sg_init ( & sg , cpu_addr , vrp - > buf_size ) ;
2011-10-20 23:10:55 +04:00
2013-03-20 09:14:29 +04:00
err = virtqueue_add_inbuf ( vrp - > rvq , & sg , 1 , cpu_addr ,
2016-08-13 02:42:26 +03:00
GFP_KERNEL ) ;
2012-10-16 17:26:15 +04:00
WARN_ON ( err ) ; /* sanity check; this can't really happen */
2011-10-20 23:10:55 +04:00
}
/* suppress "tx-complete" interrupts */
virtqueue_disable_cb ( vrp - > svq ) ;
vdev - > priv = vrp ;
/* if supported by the remote processor, enable the name service */
if ( virtio_has_feature ( vdev , VIRTIO_RPMSG_F_NS ) ) {
/* a dedicated endpoint handles the name service msgs */
vrp - > ns_ept = __rpmsg_create_ept ( vrp , NULL , rpmsg_ns_cb ,
vrp , RPMSG_NS_ADDR ) ;
if ( ! vrp - > ns_ept ) {
dev_err ( & vdev - > dev , " failed to create the ns ept \n " ) ;
err = - ENOMEM ;
goto free_coherent ;
}
}
2015-03-12 04:24:41 +03:00
/*
* Prepare to kick but don ' t notify yet - we can ' t do this before
* device is ready .
*/
notify = virtqueue_kick_prepare ( vrp - > rvq ) ;
/* From this point on, we can notify and get callbacks. */
virtio_device_ready ( vdev ) ;
2011-10-20 23:10:55 +04:00
/* tell the remote processor it can start sending messages */
2015-03-12 04:24:41 +03:00
/*
* this might be concurrent with callbacks , but we are only
* doing notify , not a full kick here , so that ' s ok .
*/
if ( notify )
virtqueue_notify ( vrp - > rvq ) ;
2011-10-20 23:10:55 +04:00
dev_info ( & vdev - > dev , " rpmsg host is online \n " ) ;
return 0 ;
free_coherent :
2014-09-16 22:33:07 +04:00
dma_free_coherent ( vdev - > dev . parent - > parent , total_buf_space ,
bufs_va , vrp - > bufs_dma ) ;
2011-10-20 23:10:55 +04:00
vqs_del :
vdev - > config - > del_vqs ( vrp - > vdev ) ;
free_vrp :
kfree ( vrp ) ;
return err ;
}
static int rpmsg_remove_device ( struct device * dev , void * data )
{
device_unregister ( dev ) ;
return 0 ;
}
2012-12-22 03:14:44 +04:00
static void rpmsg_remove ( struct virtio_device * vdev )
2011-10-20 23:10:55 +04:00
{
struct virtproc_info * vrp = vdev - > priv ;
2017-03-28 14:49:43 +03:00
size_t total_buf_space = vrp - > num_bufs * vrp - > buf_size ;
2011-10-20 23:10:55 +04:00
int ret ;
vdev - > config - > reset ( vdev ) ;
ret = device_for_each_child ( & vdev - > dev , NULL , rpmsg_remove_device ) ;
if ( ret )
dev_warn ( & vdev - > dev , " can't remove rpmsg device: %d \n " , ret ) ;
2012-02-09 17:16:41 +04:00
if ( vrp - > ns_ept )
__rpmsg_destroy_ept ( vrp , vrp - > ns_ept ) ;
2011-10-20 23:10:55 +04:00
idr_destroy ( & vrp - > endpoints ) ;
vdev - > config - > del_vqs ( vrp - > vdev ) ;
2014-09-16 22:33:07 +04:00
dma_free_coherent ( vdev - > dev . parent - > parent , total_buf_space ,
vrp - > rbufs , vrp - > bufs_dma ) ;
2011-10-20 23:10:55 +04:00
kfree ( vrp ) ;
}
static struct virtio_device_id id_table [ ] = {
{ VIRTIO_ID_RPMSG , VIRTIO_DEV_ANY_ID } ,
{ 0 } ,
} ;
static unsigned int features [ ] = {
VIRTIO_RPMSG_F_NS ,
} ;
static struct virtio_driver virtio_ipc_driver = {
. feature_table = features ,
. feature_table_size = ARRAY_SIZE ( features ) ,
. driver . name = KBUILD_MODNAME ,
. driver . owner = THIS_MODULE ,
. id_table = id_table ,
. probe = rpmsg_probe ,
2012-12-22 03:14:44 +04:00
. remove = rpmsg_remove ,
2011-10-20 23:10:55 +04:00
} ;
static int __init rpmsg_init ( void )
{
int ret ;
ret = register_virtio_driver ( & virtio_ipc_driver ) ;
2016-09-02 01:28:04 +03:00
if ( ret )
2011-10-20 23:10:55 +04:00
pr_err ( " failed to register virtio driver: %d \n " , ret ) ;
return ret ;
}
2012-07-16 11:36:51 +04:00
subsys_initcall ( rpmsg_init ) ;
2011-10-20 23:10:55 +04:00
static void __exit rpmsg_fini ( void )
{
unregister_virtio_driver ( & virtio_ipc_driver ) ;
}
module_exit ( rpmsg_fini ) ;
MODULE_DEVICE_TABLE ( virtio , id_table ) ;
MODULE_DESCRIPTION ( " Virtio-based remote processor messaging bus " ) ;
MODULE_LICENSE ( " GPL v2 " ) ;