@ -13,12 +13,14 @@
# include "hw/vfio-user/proxy.h"
# include "hw/vfio-user/trace.h"
# include "qapi/error.h"
# include "qobject/qbool.h"
# include "qobject/qdict.h"
# include "qobject/qjson.h"
# include "qobject/qnum.h"
# include "qemu/error-report.h"
# include "qemu/lockable.h"
# include "qemu/main-loop.h"
# include "qemu/thread.h"
# include "system/iothread.h"
static IOThread * vfio_user_iothread ;
@ -445,6 +447,7 @@ static ssize_t vfio_user_send_one(VFIOUserProxy *proxy, Error **errp)
}
QTAILQ_REMOVE ( & proxy - > outgoing , msg , next ) ;
proxy - > num_outgoing - - ;
if ( msg - > type = = VFIO_MSG_ASYNC ) {
vfio_user_recycle ( proxy , msg ) ;
} else {
@ -481,6 +484,11 @@ static void vfio_user_send(void *opaque)
}
qio_channel_set_aio_fd_handler ( proxy - > ioc , proxy - > ctx ,
vfio_user_recv , NULL , NULL , proxy ) ;
/* queue empty - send any pending multi write msgs */
if ( proxy - > wr_multi ! = NULL ) {
vfio_user_flush_multi ( proxy ) ;
}
}
}
@ -579,11 +587,18 @@ static bool vfio_user_send_queued(VFIOUserProxy *proxy, VFIOUserMsg *msg,
{
int ret ;
/* older coalesced writes go first */
if ( proxy - > wr_multi ! = NULL & &
( ( msg - > hdr - > flags & VFIO_USER_TYPE ) = = VFIO_USER_REQUEST ) ) {
vfio_user_flush_multi ( proxy ) ;
}
/*
* Unsent outgoing msgs - add to tail
*/
if ( ! QTAILQ_EMPTY ( & proxy - > outgoing ) ) {
QTAILQ_INSERT_TAIL ( & proxy - > outgoing , msg , next ) ;
proxy - > num_outgoing + + ;
return true ;
}
@ -598,6 +613,7 @@ static bool vfio_user_send_queued(VFIOUserProxy *proxy, VFIOUserMsg *msg,
if ( ret = = QIO_CHANNEL_ERR_BLOCK ) {
QTAILQ_INSERT_HEAD ( & proxy - > outgoing , msg , next ) ;
proxy - > num_outgoing = 1 ;
qio_channel_set_aio_fd_handler ( proxy - > ioc , proxy - > ctx ,
vfio_user_recv , proxy - > ctx ,
vfio_user_send , proxy ) ;
@ -1151,12 +1167,27 @@ static bool check_migr(VFIOUserProxy *proxy, QObject *qobj, Error **errp)
return caps_parse ( proxy , qdict , caps_migr , errp ) ;
}
static bool check_multi ( VFIOUserProxy * proxy , QObject * qobj , Error * * errp )
{
QBool * qb = qobject_to ( QBool , qobj ) ;
if ( qb = = NULL ) {
error_setg ( errp , " malformed %s " , VFIO_USER_CAP_MULTI ) ;
return false ;
}
if ( qbool_get_bool ( qb ) ) {
proxy - > flags | = VFIO_PROXY_USE_MULTI ;
}
return true ;
}
static struct cap_entry caps_cap [ ] = {
{ VFIO_USER_CAP_MAX_FDS , check_max_fds } ,
{ VFIO_USER_CAP_MAX_XFER , check_max_xfer } ,
{ VFIO_USER_CAP_PGSIZES , check_pgsizes } ,
{ VFIO_USER_CAP_MAP_MAX , check_max_dma } ,
{ VFIO_USER_CAP_MIGR , check_migr } ,
{ VFIO_USER_CAP_MULTI , check_multi } ,
{ NULL }
} ;
@ -1215,6 +1246,7 @@ static GString *caps_json(void)
qdict_put_int ( capdict , VFIO_USER_CAP_MAX_XFER , VFIO_USER_DEF_MAX_XFER ) ;
qdict_put_int ( capdict , VFIO_USER_CAP_PGSIZES , VFIO_USER_DEF_PGSIZE ) ;
qdict_put_int ( capdict , VFIO_USER_CAP_MAP_MAX , VFIO_USER_DEF_MAP_MAX ) ;
qdict_put_bool ( capdict , VFIO_USER_CAP_MULTI , true ) ;
qdict_put_obj ( dict , VFIO_USER_CAP , QOBJECT ( capdict ) ) ;
@ -1270,3 +1302,55 @@ bool vfio_user_validate_version(VFIOUserProxy *proxy, Error **errp)
trace_vfio_user_version ( msgp - > major , msgp - > minor , msgp - > capabilities ) ;
return true ;
}
void vfio_user_flush_multi ( VFIOUserProxy * proxy )
{
VFIOUserMsg * msg ;
VFIOUserWRMulti * wm = proxy - > wr_multi ;
Error * local_err = NULL ;
proxy - > wr_multi = NULL ;
/* adjust size for actual # of writes */
wm - > hdr . size - = ( VFIO_USER_MULTI_MAX - wm - > wr_cnt ) * sizeof ( VFIOUserWROne ) ;
msg = vfio_user_getmsg ( proxy , & wm - > hdr , NULL ) ;
msg - > id = wm - > hdr . id ;
msg - > rsize = 0 ;
msg - > type = VFIO_MSG_ASYNC ;
trace_vfio_user_wrmulti ( " flush " , wm - > wr_cnt ) ;
if ( ! vfio_user_send_queued ( proxy , msg , & local_err ) ) {
error_report_err ( local_err ) ;
vfio_user_recycle ( proxy , msg ) ;
}
}
void vfio_user_create_multi ( VFIOUserProxy * proxy )
{
VFIOUserWRMulti * wm ;
wm = g_malloc0 ( sizeof ( * wm ) ) ;
vfio_user_request_msg ( & wm - > hdr , VFIO_USER_REGION_WRITE_MULTI ,
sizeof ( * wm ) , VFIO_USER_NO_REPLY ) ;
proxy - > wr_multi = wm ;
}
void vfio_user_add_multi ( VFIOUserProxy * proxy , uint8_t index ,
off_t offset , uint32_t count , void * data )
{
VFIOUserWRMulti * wm = proxy - > wr_multi ;
VFIOUserWROne * w1 = & wm - > wrs [ wm - > wr_cnt ] ;
w1 - > offset = offset ;
w1 - > region = index ;
w1 - > count = count ;
memcpy ( & w1 - > data , data , count ) ;
wm - > wr_cnt + + ;
trace_vfio_user_wrmulti ( " add " , wm - > wr_cnt ) ;
if ( wm - > wr_cnt = = VFIO_USER_MULTI_MAX | |
proxy - > num_outgoing < VFIO_USER_OUT_LOW ) {
vfio_user_flush_multi ( proxy ) ;
}
}