VirtualBox

Changeset 82863 in vbox for trunk/src/VBox


Ignore:
Timestamp:
Jan 27, 2020 5:11:30 AM (5 years ago)
Author:
vboxsync
Message:

Network/DevVirtioNet_1_0.cpp: Builds cleanly. Finished initial tying together of events/notifications. See BugRef(8651) #52

Location:
trunk/src/VBox/Devices
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp

    r82827 r82863  
    3131#define LOG_GROUP LOG_GROUP_DEV_VIRTIO
    3232#define VIRTIONET_WITH_GSO
    33 #define VIRTIONET_WITH_MERGEABLE_RX_BUFS
    3433
    3534#include <VBox/vmm/pdmdev.h>
     
    6059#include "VBoxDD.h"
    6160
    62 
    6361#define VIRTIONET_SAVED_STATE_VERSION          UINT32_C(1)
    6462#define VIRTIONET_MAX_QPAIRS                   512
     
    6967#define VIRTIONET_PREALLOCATE_RX_SEG_COUNT     32
    7068
    71 #define QUEUE_NAME(a_pVirtio, a_idxQueue)   ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName)
    72 #define VIRTQNAME(qIdx) (pThis->aszVirtqNames[qIdx])
    73 #define CBVIRTQNAME(qIdx) RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx)))
    74 #define FEATURE_ENABLED(feature) (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
     69#define INSTANCE(pState) pState->szInstanceName
     70#define QUEUE_NAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName)
     71#define VIRTQNAME(qIdx)           (pThis->aszVirtqNames[qIdx])
     72#define CBVIRTQNAME(qIdx)         RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx)))
     73#define FEATURE_ENABLED(feature)  (pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
    7574#define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature))
    76 #define FEATURE_OFFERED(feature) (VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature)
    77 #define INSTANCE(pState) pState->szInstanceName;
     75#define FEATURE_OFFERED(feature)  (VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature)
    7876
    7977#define SET_LINK_UP(pState) \
     
    8583            virtioCoreNotifyConfigChanged(&pThis->Virtio)
    8684
    87 #define IS_LINK_UP(pState)  (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP)
     85#define IS_LINK_UP(pState)   (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP)
    8886#define IS_LINK_DOWN(pState) !IS_LINK_UP(pState)
    8987
    9088/* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */
    91 #define RXQIDX(qPairIdx)  (qPairIdx * 2)
    92 #define TXQIDX(qPairIdx)  (qPairIdx * 2 + 1)
    93 #define CTRLQIDX          ((pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) ? VIRTIONET_MAX_QPAIRS * 2 + 2 : 4)
    94 
    95 #define RXVIRTQNAME(qPairIdx)  (pThis->aszVirtqNames[RXQIDX(qPairIdx)])
    96 #define TXVIRTQNAME(qPairIdx)  (pThis->aszVirtqNames[TXQIDX(qPairIdx)])
     89#define IS_TX_QUEUE(n)    ((n) != CTRLQIDX && ((n) & 1))
     90#define IS_RX_QUEUE(n)    ((n) != CTRLQIDX && !IS_TX_QUEUE(n))
     91#define IS_CTRL_QUEUE(n)  ((n) == CTRLQIDX)
     92#define RXQIDX_QPAIR(qPairIdx)  (qPairIdx * 2)
     93#define TXQIDX_QPAIR(qPairIdx)  (qPairIdx * 2 + 1)
     94#define CTRLQIDX          ((pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) ? ((VIRTIONET_MAX_QPAIRS - 1) * 2 + 2) : (2))
     95
     96#define RXVIRTQNAME(qPairIdx)  (pThis->aszVirtqNames[RXQIDX_QPAIR(qPairIdx)])
     97#define TXVIRTQNAME(qPairIdx)  (pThis->aszVirtqNames[TXQIDX_QPAIR(qPairIdx)])
    9798#define CTLVIRTQNAME(qPairIdx) (pThis->aszVirtqNames[CTRLQIDX])
    9899
     
    154155    | VIRTIONET_F_CTRL_RX               \
    155156    | VIRTIONET_F_CTRL_VLAN             \
    156     | VIRTIONET_HOST_FEATURES_GSO
     157    | VIRTIONET_HOST_FEATURES_GSO       \
     158    | VIRTIONET_F_MRG_RXBUF
    157159
    158160#define PCI_DEVICE_ID_VIRTIONET_HOST               0x1041      /**< Informs guest driver of type of VirtIO device   */
     
    185187#pragma pack()
    186188
    187 #define VIRTIONET_F_LINK_UP                RT_BIT_16(1)         /**< config status: Link is up                      */
    188 #define VIRTIONET_F_ANNOUNCE               RT_BIT_16(2)         /**< config status: Announce                        */
     189#define VIRTIONET_F_LINK_UP                  RT_BIT(1)          /**< config status: Link is up                      */
     190#define VIRTIONET_F_ANNOUNCE                 RT_BIT(2)          /**< config status: Announce                        */
    189191
    190192/** @name VirtIO 1.0 NET Host Device device specific control types
     
    347349    uint64_t                fNegotiatedFeatures;
    348350
    349 #ifdef VIRTIONET_TX_DELAY
    350     /** Transmit Delay Timer. */
    351     TMTIMERHANDLE           hTxTimer;
    352     uint32_t                ui;
    353     uint32_t                uAvgDiff;
    354     uint32_t                uMinDiff;
    355     uint32_t                uMaxDiff;
    356     uint64_t                u64NanoTS;
    357 #else  /* !VNET_TX_DELAY */
    358     /** The event semaphore TX thread waits on. */
    359351    SUPSEMEVENT             hTxEvent;
    360 #endif /* !VNET_TX_DELAY */
    361352
    362353    /** Indicates transmission in progress -- only one thread is allowed. */
     
    381372
    382373    /** N/A: */
    383     bool volatile           fMaybeOutOfSpace;
     374    bool volatile           fLeafWantsRxBuffers;
    384375
    385376    /** Flags whether VirtIO core is in ready state */
     
    399390
    400391    /** No multicast mode - Supresses multicast receive */
    401     uint8_t                 fNoMulticat;
     392    uint8_t                 fNoMulticast;
    402393
    403394    /** No unicast mode - Suppresses unicast receive */
     
    420411
    421412    /** Bit array of VLAN filter, one bit per VLAN ID. */
    422     uint8_t                 aVlanFilter[VIRTIONET_MAX_VID / sizeof(uint8_t)];
     413    uint8_t                 aVlanFilter[VIRTIONET_MAX_VLAN_ID / sizeof(uint8_t)];
    423414
    424415    /* Receive-blocking-related fields ***************************************/
    425416
    426417    /** EMT: Gets signalled when more RX descriptors become available. */
    427     SUPSEMEVENT             hEventMoreRxDescAvail;
    428 
    429     /** Handle of the I/O port range.  */
    430     IOMIOPORTHANDLE         hIoPorts;
    431 
    432     /** @name Statistic
    433      * @{ */
    434     STAMCOUNTER             StatReceiveBytes;
    435     STAMCOUNTER             StatTransmitBytes;
    436     STAMCOUNTER             StatReceiveGSO;
    437     STAMCOUNTER             StatTransmitPackets;
    438     STAMCOUNTER             StatTransmitGSO;
    439     STAMCOUNTER             StatTransmitChksum;
    440 #ifdef VBOX_WITH_STATISTICS
    441     STAMPROFILE             StatReceive;
    442     STAMPROFILE             StatReceiveStore;
    443     STAMPROFILEADV          StatTransmit;
    444     STAMPROFILE             StatTransmitSend;
    445     STAMPROFILE             StatRxOverflow;
    446     STAMCOUNTER             StatRxOverflowWakeup;
    447     STAMCOUNTER             StatTransmitByNetwork;
    448     STAMCOUNTER             StatTransmitByThread;
    449 #endif
     418    SUPSEMEVENT             hEventRxDescAvail;
     419
    450420} VIRTIONET;
    451421/** Pointer to the shared state of the VirtIO Host NET device. */
     
    493463    R3PTRTYPE(PPDMINETWORKUP)       pDrv;
    494464
    495 #ifndef VIRTIONET_TX_DELAY
    496465    R3PTRTYPE(PPDMTHREAD)           pTxThread;
    497 #endif
    498466
    499467    /** Link Up(/Restore) Timer. */
     
    547515#ifdef IN_RING3 /* spans most of the file, at the moment. */
    548516
     517/**
     518 * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
     519 */
     520static DECLCALLBACK(int) virtioNetR3WakeupWorker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
     521{
     522    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     523    return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[(uintptr_t)pThread->pvUser].hEvtProcess);
     524}
     525
     526/**
     527 * Wakeup the RX thread.
     528 */
     529static void virtioNetR3WakeupRxBufWaiter(PPDMDEVINS pDevIns)
     530{
     531    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     532
     533    AssertReturnVoid(pThis->hEventRxDescAvail != NIL_SUPSEMEVENT);
     534    AssertReturnVoid(ASMAtomicReadBool(&pThis->fLeafWantsRxBuffers));
     535
     536    Log(("%s Waking downstream driver's Rx buf waiter thread\n", INSTANCE(pThis)));
     537    int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail);
     538    AssertRC(rc);
     539}
    549540
    550541DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis)
     
    552543    for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++)
    553544    {
    554         RTStrPrintf(pThis->aszVirtqNames[RXQIDX(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>",  qPairIdx);
    555         RTStrPrintf(pThis->aszVirtqNames[TXQIDX(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx);
     545        RTStrPrintf(pThis->aszVirtqNames[RXQIDX_QPAIR(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>",  qPairIdx);
     546        RTStrPrintf(pThis->aszVirtqNames[TXQIDX_QPAIR(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx);
    556547    }
    557548    RTStrCopy(pThis->aszVirtqNames[CTRLQIDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
    558549}
    559550
     551/**
     552 * Dump a packet to debug log.
     553 *
     554 * @param   pThis       The virtio-net shared instance data.
     555 * @param   pbPacket    The packet.
     556 * @param   cb          The size of the packet.
     557 * @param   pszText     A string denoting direction of packet transfer.
     558 */
     559DECLINLINE(void) virtioNetR3PacketDump(PVIRTIONET pThis, const uint8_t *pbPacket, size_t cb, const char *pszText)
     560{
     561# ifdef DEBUG
     562#  if 0
     563    Log(("%s %s packet #%d (%d bytes):\n",
     564         INSTANCE(pThis), pszText, ++pThis->u32PktNo, cb));
     565    Log3(("%.*Rhxd\n", cb, pbPacket));
     566#  else
     567    vboxEthPacketDump(INSTANCE(pThis), pszText, pbPacket, (uint32_t)cb);
     568#  endif
     569# else
     570    RT_NOREF4(pThis, pbPacket, cb, pszText);
     571# endif
     572}
    560573
    561574DECLINLINE(void) virtioNetPrintFeatures(PVIRTIONET pThis, uint32_t fFeatures, const char *pcszText)
     
    641654}
    642655
    643 /**
    644  * @callback_method_impl{VIRTIOCORER3,pfnQueueNotified}
    645  */
    646 static DECLCALLBACK(void) virtioNetR3Notified(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint16_t qIdx)
    647 {
    648     PVIRTIONET         pThis     = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio);
    649     PVIRTIONETCC       pThisCC   = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio);
    650     PPDMDEVINS         pDevIns   = pThisCC->pDevIns;
    651     AssertReturnVoid(qIdx < pThis->cVirtQueues);
    652     PVIRTIONETWORKER   pWorker   = &pThis->aWorkers[qIdx];
    653     PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[qIdx];
    654 
    655 #ifdef LOG_ENABLED
    656     RTLogFlush(NULL);
    657 #endif
    658 
    659     Log6Func(("%s has available data\n", VIRTQNAME(qIdx)));
    660     /* Wake queue's worker thread up if sleeping */
    661     if (!ASMAtomicXchgBool(&pWorkerR3->fNotified, true))
    662     {
    663         if (ASMAtomicReadBool(&pWorkerR3->fSleeping))
    664         {
    665             Log6Func(("waking %s worker.\n", VIRTQNAME(qIdx)));
    666             int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    667             AssertRC(rc);
    668         }
    669     }
    670 }
     656
    671657
    672658
     
    725711
    726712
    727 #if 0
    728 
    729713static int virtioNetR3CfgAccessed(PVIRTIONET pThis, uint32_t offConfig, void *pv, uint32_t cb, bool fWrite)
    730714{
     
    733717    if (MATCH_NET_CONFIG(uMacAddress))
    734718        NET_CONFIG_ACCESSOR_READONLY(uMacAddress);
    735 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_STATUS
     719#if FEATURE_OFFERED(STATUS)
    736720    else
    737721    if (MATCH_NET_CONFIG(uStatus))
    738722        NET_CONFIG_ACCESSOR_READONLY(uStatus);
    739723#endif
    740 #if VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_MQ
     724#if FEATURE_OFFERED(MQ)
    741725    else
    742726    if (MATCH_NET_CONFIG(uMaxVirtqPairs))
     
    771755    return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
    772756}
    773 
    774 #endif
    775757
    776758
     
    940922     */
    941923
     924    virtioNetR3WakeupRxBufWaiter(pDevIns);
     925
    942926    virtioNetR3QuiesceDevice(pDevIns, enmType);
     927
    943928}
    944929
     
    991976}
    992977
    993 /**
    994  * @callback_method_impl{FNIOMIOPORTNEWIN}
    995  */
    996 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortIn(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t *pu32, unsigned cb)
    997 {
    998     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    999     RT_NOREF(pvUser);
    1000     return vpciIOPortIn(pDevIns, &pThis->VPCI, offPort, pu32, cb, &g_IOCallbacks);
    1001 }
    1002 
    1003 
    1004 /**
    1005  * @callback_method_impl{FNIOMIOPORTNEWOUT}
    1006  */
    1007 static DECLCALLBACK(VBOXSTRICTRC) vnetIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint32_t u32, unsigned cb)
    1008 {
    1009     PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1010     PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    1011     RT_NOREF(pvUser);
    1012     return vpciIOPortOut(pDevIns, &pThis->VPCI, &pThisCC->VPCI, offPort, u32, cb, &g_IOCallbacks);
    1013 }
    1014 
    1015978
    1016979#ifdef IN_RING3
    1017 /**
    1018  * @interface_method_impl{PDMIBASE,pfnQueryInterface,
    1019  * For VNETSTATECC::VPCI.IBase}
    1020  */
    1021 static DECLCALLBACK(void *) virtioNetQueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
    1022 {
    1023     PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, VPCI.IBase);
    1024 
    1025     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown);
    1026     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
    1027 
    1028     return vpciR3QueryInterface(&pThisCC->VPCI, pszIID);
    1029 }
    1030 
    1031 /**
    1032  * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
    1033  */
    1034 static DECLCALLBACK(int) virtioNetR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)
    1035 {
    1036     PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1037     PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown);
    1038     PPDMDEVINS   pDevIns = pThisCC->pDevIns;
    1039 
    1040     LogFlowFunc(("%s: cMillies=%u\n", INSTANCE(pThis), cMillies));
    1041 
    1042     int rc = virtioNetR3CanReceive(pDevIns, pThis, pThisCC);
    1043     if (RT_SUCCESS(rc))
    1044         return VINF_SUCCESS;
    1045 
    1046     if (cMillies == 0)
    1047         return VERR_NET_NO_BUFFER_SPACE;
    1048 
    1049     rc = VERR_INTERRUPTED;
    1050     ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, true);
    1051     STAM_PROFILE_START(&pThis->StatRxOverflow, a);
    1052 
    1053     VMSTATE enmVMState;
    1054     while (RT_LIKELY(  (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING
    1055                      || enmVMState == VMSTATE_RUNNING_LS))
    1056     {
    1057         int rc2 = virtioNetR3CanReceive(pDevIns, pThis, pThisCC);
    1058         if (RT_SUCCESS(rc2))
    1059         {
    1060             rc = VINF_SUCCESS;
    1061             break;
    1062         }
    1063         LogFunc(("%s: waiting cMillies=%u...\n", INSTANCE(pThis), cMillies));
    1064         rc2 = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventMoreRxDescAvail, cMillies);
    1065         if (RT_FAILURE(rc2) && rc2 != VERR_TIMEOUT && rc2 != VERR_INTERRUPTED)
    1066             RTThreadSleep(1);
    1067     }
    1068     STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
    1069     ASMAtomicXchgBool(&pThis->fMaybeOutOfSpace, false);
    1070 
    1071     LogFlowFunc(("%s: -> %d\n", INSTANCE(pThis), rc));
    1072     return rc;
    1073 }
     980
     981
     982DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb)
     983{
     984    uint32_t  chksum = 0;
     985    uint16_t *pu = (uint16_t *)pvBuf;
     986
     987    while (cb > 1)
     988    {
     989        chksum += *pu++;
     990        cb -= 2;
     991    }
     992    if (cb)
     993        chksum += *(uint8_t*)pu;
     994    while (chksum >> 16)
     995        chksum = (chksum >> 16) + (chksum & 0xFFFF);
     996    return ~chksum;
     997}
     998
     999DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset)
     1000{
     1001    AssertReturnVoid(uStart < cbSize);
     1002    AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize);
     1003    *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Checkum16(pBuf + uStart, cbSize - uStart);
     1004}
     1005
     1006/**
     1007 * Turns on/off the read status LED.
     1008 *
     1009 * @returns VBox status code.
     1010 * @param   pThis          Pointer to the device state structure.
     1011 * @param   fOn             New LED state.
     1012 */
     1013void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn)
     1014{
     1015    Log6Func(("%s\n", fOn ? "on" : "off"));
     1016    if (fOn)
     1017        pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1;
     1018    else
     1019        pThisR3->led.Actual.s.fReading = fOn;
     1020}
     1021
     1022/**
     1023 * Turns on/off the write status LED.
     1024 *
     1025 * @returns VBox status code.
     1026 * @param   pThis          Pointer to the device state structure.
     1027 * @param   fOn            New LED state.
     1028 */
     1029void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn)
     1030{
     1031    Log6Func(("%s\n", fOn ? "on" : "off"));
     1032    if (fOn)
     1033        pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1;
     1034    else
     1035        pThisR3->led.Actual.s.fWriting = fOn;
     1036}
     1037
    10741038/**
    10751039 * Check if the device can receive data now.
     
    10831047 * @thread  RX
    10841048 */
    1085 static int virtioNetR3CanReceive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    1086 {
    1087     int rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY);
    1088     AssertRCReturn(rc, rc);
     1049static int virtioNetR3IsRxQueuePrimed(PPDMDEVINS pDevIns, PVIRTIONET pThis)
     1050{
     1051    int rc;
    10891052
    10901053    LogFlowFunc(("%s:\n", INSTANCE(pThis)));
     
    10931056        rc = VERR_NET_NO_BUFFER_SPACE;
    10941057
    1095     else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, RXQIDX(0)))
     1058    else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, RXQIDX_QPAIR(0)))
    10961059        rc = VERR_NET_NO_BUFFER_SPACE;
    10971060
    1098     else if (virtioCoreQueueIsEmpty(pDevIns, pThis->Virtio, RXQIDX(0)))
    1099     {
    1100         virtioCoreQueueSetNotify(&pThis->pVirtio, RXQIDX(0), true);
     1061    else if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0)))
     1062    {
     1063        virtioCoreQueueSetNotify(&pThis->Virtio, RXQIDX_QPAIR(0), true);
    11011064        rc = VERR_NET_NO_BUFFER_SPACE;
    11021065    }
    11031066    else
    11041067    {
    1105         virtioCoreQueueSetNotify(&pThis->pVirtio, RXQIDX(0), false);
     1068        virtioCoreQueueSetNotify(&pThis->Virtio, RXQIDX_QPAIR(0), false);
    11061069        rc = VINF_SUCCESS;
    11071070    }
    11081071
    11091072    LogFlowFunc(("%s: -> %Rrc\n", INSTANCE(pThis), rc));
    1110     virtioNetCsRxLeave(pThis);
    11111073    return rc;
    11121074}
    1113 /**
    1114  * @callback_method_impl{FNTMTIMERDEV, Link Up Timer handler.}
    1115  */
    1116 static DECLCALLBACK(void) virtioNetR3LinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    1117 {
    1118     PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1119     PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    1120     RT_NOREF(pTimer, pvUser);
    1121 
    1122     int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY);
    1123     AssertRCReturnVoid(rc);
    1124 
    1125     SET_LINK_UP(pThis);
    1126 
    1127     virtioNetWakeupReceive(pDevIns);
    1128 
    1129     virtioNetR3CsLeave(pDevIns, pThis);
    1130 
    1131     LogFunc(("%s: Link is up\n", INSTANCE(pThis)));
    1132     if (pThisCC->pDrv)
    1133         pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP);
    1134 }
    1135 
    1136 
    1137 /**
    1138  * Takes down the link temporarily if it's current status is up.
    1139  *
    1140  * This is used during restore and when replumbing the network link.
    1141  *
    1142  * The temporary link outage is supposed to indicate to the OS that all network
    1143  * connections have been lost and that it for instance is appropriate to
    1144  * renegotiate any DHCP lease.
    1145  *
    1146  * @param   pDevIns     The device instance.
    1147  * @param   pThis       The virtio-net shared instance data.
    1148  * @param   pThisCC     The virtio-net ring-3 instance data.
    1149  */
    1150 static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    1151 {
    1152     if (IS_LINK_UP(pThis))
    1153     {
    1154         SET_LINK_DOWN(pThis);
    1155 
    1156         /* Restore the link back in 5 seconds. */
    1157         int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay);
    1158         AssertRC(rc);
    1159 
    1160         LogFunc(("%s: Link is down temporarily\n", INSTANCE(pThis)));
    1161     }
    1162 }
    1163 
    1164 /**
    1165  * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
    1166  */
    1167 static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface)
    1168 {
    1169     PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
    1170 
    1171     return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN;
    1172 }
    1173 
    1174 /**
    1175  * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState}
    1176  */
    1177 static DECLCALLBACK(int) virtioNetR3NetworkConfig_SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
    1178 {
    1179     PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkConfig);
     1075
     1076/**
     1077 * @interface_method_impl{PDMINETWORKDOWN,pfnWaitReceiveAvail}
     1078 */
     1079static DECLCALLBACK(int) virtioNetR3NetworkDown_WaitReceiveAvail(PPDMINETWORKDOWN pInterface, RTMSINTERVAL timeoutMs)
     1080{
     1081    PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
    11801082    PPDMDEVINS   pDevIns = pThisCC->pDevIns;
    11811083    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    11821084
    1183     bool fOldUp = !!(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP);
    1184     bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
    1185 
    1186     Log(("%s virtioNetR3NetworkConfig_SetLinkState: enmState=%d\n", INSTANCE(pThis), enmState));
    1187     if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME)
    1188     {
    1189         if (fOldUp)
     1085    LogFlowFunc(("%s: timeoutMs=%u\n", INSTANCE(pThis), timeoutMs));
     1086
     1087    if (!timeoutMs)
     1088        return VERR_NET_NO_BUFFER_SPACE;
     1089
     1090    ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, true);
     1091
     1092    VMSTATE enmVMState;
     1093    while (RT_LIKELY(  (enmVMState = PDMDevHlpVMState(pDevIns)) == VMSTATE_RUNNING
     1094                     || enmVMState == VMSTATE_RUNNING_LS))
     1095    {
     1096
     1097        if (RT_SUCCESS(virtioNetR3IsRxQueuePrimed(pDevIns, pThis)))
    11901098        {
    1191             /*
    1192              * We bother to bring the link down only if it was up previously. The UP link state
    1193              * notification will be sent when the link actually goes up in virtioNetR3LinkUpTimer().
    1194              */
    1195             virtioNetR3TempLinkDown(pDevIns, pThis, pThisCC);
    1196             if (pThisCC->pDrv)
    1197                 pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState);
     1099            LogFunc(("Rx bufs now available, releasing waiter..."));
     1100            return VINF_SUCCESS;
    11981101        }
    1199     }
    1200     else if (fNewUp != fOldUp)
    1201     {
    1202         if (fNewUp)
    1203         {
    1204             Log(("%s Link is up\n", INSTANCE(pThis)));
    1205             pThis->fCableConnected = true;
    1206             pThis->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP;
    1207             virtioCoreNotifyConfigChanged(&pThis->Virtio);
    1208         }
    1209         else
    1210         {
    1211             /* The link was brought down explicitly, make sure it won't come up by timer.  */
    1212             PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer);
    1213             Log(("%s Link is down\n", INSTANCE(pThis)));
    1214             pThis->fCableConnected = false;
    1215             pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP;
    1216             virtioCoreNotifyConfigChanged(&pThis->Virtio);
    1217         }
    1218         if (pThisCC->pDrv)
    1219             pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState);
    1220     }
    1221     return VINF_SUCCESS;
    1222 }
    1223 
    1224 /**
    1225  * @callback_method_impl{FNVPCIQUEUECALLBACK, The RX queue}
    1226  */
    1227 static DECLCALLBACK(void) virtioNetR3QueueReceive(PPDMDEVINS pDevIns, PVQUEUE pQueue)
    1228 {
    1229     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1230     RT_NOREF(pThis, pQueue);
    1231     LogFunc(("%s Receive buffers has been added, waking up receive thread.\n", INSTANCE(pThis)));
    1232     virtioNetWakeupReceive(pDevIns);
    1233 }
     1102        LogFunc(("%s: Starved for guest Rx bufs, waiting %u ms ...\n", INSTANCE(pThis), timeoutMs));
     1103
     1104        int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs);
     1105        if (RT_FAILURE(rc) && rc != VERR_TIMEOUT && rc != VERR_INTERRUPTED)
     1106            RTThreadSleep(1);
     1107    }
     1108    ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, false);
     1109
     1110    LogFlowFunc(("%s: Wait for Rx buffers available was interrupted\n", INSTANCE(pThis)));
     1111    return VERR_INTERRUPTED;
     1112}
     1113
    12341114
    12351115/**
     
    12391119 * @param   pCtx                The context descriptor.
    12401120 */
    1241 DECLINLINE(PPDMNETWORKGSO) virtioNetR3SetupGsoCtx(PPDMNETWORKGSO pGso, VNETHDR const *pHdr)
     1121DECLINLINE(PPDMNETWORKGSO) virtioNetR3SetupGsoCtx(PPDMNETWORKGSO pGso, VIRTIONET_PKT_HDR_T const *pPktHdr)
    12421122{
    12431123    pGso->u8Type = PDMNETWORKGSOTYPE_INVALID;
    12441124
    1245     if (pHdr->u8GSOType & VNETHDR_GSO_ECN)
     1125    if (pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN)
    12461126    {
    12471127        AssertMsgFailed(("Unsupported flag in virtio header: ECN\n"));
    12481128        return NULL;
    12491129    }
    1250     switch (pHdr->u8GSOType & ~VNETHDR_GSO_ECN)
    1251     {
    1252         case VNETHDR_GSO_TCPV4:
     1130    switch (pPktHdr->uGsoType & ~VIRTIONET_HDR_GSO_ECN)
     1131    {
     1132        case VIRTIONET_HDR_GSO_TCPV4:
    12531133            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_TCP;
    1254             pGso->cbHdrsSeg = pHdr->u16HdrLen;
     1134            pGso->cbHdrsSeg = pPktHdr->uHdrLen;
    12551135            break;
    1256         case VNETHDR_GSO_TCPV6:
     1136        case VIRTIONET_HDR_GSO_TCPV6:
    12571137            pGso->u8Type = PDMNETWORKGSOTYPE_IPV6_TCP;
    1258             pGso->cbHdrsSeg = pHdr->u16HdrLen;
     1138            pGso->cbHdrsSeg = pPktHdr->uHdrLen;
    12591139            break;
    1260         case VNETHDR_GSO_UDP:
     1140        case VIRTIONET_HDR_GSO_UDP:
    12611141            pGso->u8Type = PDMNETWORKGSOTYPE_IPV4_UDP;
    1262             pGso->cbHdrsSeg = pHdr->u16CSumStart;
     1142            pGso->cbHdrsSeg = pPktHdr->uChksumStart;
    12631143            break;
    12641144        default:
    12651145            return NULL;
    12661146    }
    1267     if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM)
    1268         pGso->offHdr2  = pHdr->u16CSumStart;
     1147    if (pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)
     1148        pGso->offHdr2  = pPktHdr->uChksumStart;
    12691149    else
    12701150    {
     
    12731153    }
    12741154    pGso->offHdr1     = sizeof(RTNETETHERHDR);
    1275     pGso->cbHdrsTotal = pHdr->u16HdrLen;
    1276     pGso->cbMaxSeg    = pHdr->u16GSOSize;
     1155    pGso->cbHdrsTotal = pPktHdr->uHdrLen;
     1156    pGso->cbMaxSeg    = pPktHdr->uGsoSize;
    12771157    return pGso;
    12781158}
     
    12801160
    12811161/**
    1282  * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
    1283  */
    1284 static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
    1285 {
    1286     return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL);
    1287 }
    1288 
    1289 /**
    12901162 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetMac}
    12911163 */
    12921164static DECLCALLBACK(int) virtioNetR3NetworkConfig_GetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
    12931165{
    1294     PVNETSTATECC    pThisCC = RT_FROM_MEMBER(pInterface, VNETSTATECC, INetworkConfig);
    1295     PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVNETSTATE);
     1166    PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig);
     1167    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
    12961168    memcpy(pMac, pThis->virtioNetConfig.uMacAddress.au8, sizeof(RTMAC));
    12971169    return VINF_SUCCESS;
    12981170}
    1299 #endif
    13001171
    13011172/**
     
    13391210
    13401211    /* Compare TPID with VLAN Ether Type */
    1341     if (   uPtr[6] == RT_H2BE_u(0x8100)
    1342         && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_u(uPtr[7]) & 0xFFF))
    1343     {
    1344         Log4func(("%s: not our VLAN, returning false\n", INSTANCE(pThis))));
     1212    if (   uPtr[6] == RT_H2BE_U16(0x8100)
     1213        && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF))
     1214    {
     1215        Log4Func(("%s: not our VLAN, returning false\n", INSTANCE(pThis)));
    13451216        return false;
    13461217    }
     
    13551226        return true;
    13561227
    1357     Log4func(("%s : %RTmac (conf) != %RTmac (dest)\n",
     1228    Log4Func(("%s : %RTmac (conf) != %RTmac (dest)\n",
    13581229        INSTANCE(pThis), pThis->virtioNetConfig.uMacAddress.au8, pvBuf));
    13591230
     
    13691240
    13701241    Log2Func(("%s: failed all tests, returning false, packet dump follows:\n",
    1371         INSTANCE(pThis))));
     1242        INSTANCE(pThis)));
    13721243
    13731244    virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     
    13921263 * @thread  RX
    13931264 */
     1265
     1266/*  static void virtioNetR3Receive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)
     1267{
     1268    RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain);
     1269}
     1270*/
    13941271static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    13951272                                const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)
    13961273{
     1274    RT_NOREF(pThisCC);
     1275
    13971276    VIRTIONET_PKT_HDR_T rxPktHdr;
    13981277
     
    14001279    {
    14011280        Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    1402               INSTANCE(pThis), pGso->uType, pGso->cbHdrsTotal,
     1281              INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal,
    14031282              pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
    14041283
    14051284        rxPktHdr.uFlags = VIRTIONET_HDR_F_NEEDS_CSUM;
    1406         switch (pGso->uType)
     1285        switch (pGso->u8Type)
    14071286        {
    14081287            case PDMNETWORKGSOTYPE_IPV4_TCP:
    14091288                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV4;
    1410                 rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
     1289                rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
    14111290                break;
    14121291            case PDMNETWORKGSOTYPE_IPV6_TCP:
    14131292                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_TCPV6;
    1414                 rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
     1293                rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETTCP, th_sum);
    14151294                break;
    14161295            case PDMNETWORKGSOTYPE_IPV4_UDP:
    14171296                rxPktHdr.uGsoType = VIRTIONET_HDR_GSO_UDP;
    1418                 rxPktHdr.uCSumOffset = RT_OFFSETOF(RTNETUDP, uh_sum);
     1297                rxPktHdr.uChksumOffset = RT_OFFSETOF(RTNETUDP, uh_sum);
    14191298                break;
    14201299            default:
     
    14221301        }
    14231302        rxPktHdr.uHdrLen = pGso->cbHdrsTotal;
    1424         rxPktHdr.uGSOSize = pGso->cbMaxSeg;
    1425         rxPktHdr.uCSumStart = pGso->offHdr2;
    1426         STAM_REL_COUNTER_INC(&pThis->StatReceiveGSO);
     1303        rxPktHdr.uGsoSize = pGso->cbMaxSeg;
     1304        rxPktHdr.uChksumOffset = pGso->offHdr2;
    14271305    }
    14281306    else
     
    14341312    virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
    14351313
    1436     PRTSGBUF pSegsBuf;
    1437     PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2);
    1438     AssertReturn(paSegs, VERR_NO_MEMORY);
    1439     RTSgBufInit(pSegsBuf, paSegs, cSegs);
    1440 
    1441     RTGCPHYS physPktHdrNumBufs, cDescs = 0;
     1314    uint16_t cSegsAllocated = VIRTIONET_PREALLOCATE_RX_SEG_COUNT;
     1315
     1316    PRTSGBUF pVirtSegBufToGuest = NULL;
     1317    PRTSGSEG paVirtSegsToGuest = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegsAllocated);
     1318    AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY);
     1319
     1320    RTGCPHYS gcPhysPktHdrNumBuffers;
     1321    uint32_t cDescs = 0;
    14421322
    14431323    uint8_t fAddPktHdr = true;
    1444     for (uint32_t uOffset = 0; uOffset < cb; )
     1324    uint32_t uOffset;
     1325
     1326    while (uOffset < cb)
    14451327    {
    14461328        PVIRTIO_DESC_CHAIN_T pDescChain;
    1447         int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX(0), &pDescChain, true);
    1448 
    1449         AssertRC(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, rc);
     1329        int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0), &pDescChain, true);
     1330
     1331        AssertRC(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE);
    14501332
    14511333        /** @todo  Find a better way to deal with this */
     
    14551337                        VERR_INTERNAL_ERROR);
    14561338
    1457         /* It's almost inconceivable that the first segment of the guest Rx s/g buf is smaller
    1458          * than 12 bytes (i.e. size of virtio_net_hdr). Smaller hasn't been seen in practice.
    1459          * To simplify the code, that constraint is implemented here. If a guest OS ever violates
    1460          * this assumption, the algorithm can be adapted handle the more complex corner case. */
    1461 
     1339        /* Unlikely that len of 1st seg of guest Rx (IN) buf is less than sizeof(virtio_net_hdr) == 12.
     1340         * Assert it to reduce complexity. Robust solution would entail finding seg idx and offset of
     1341         * virtio_net_header.num_buffers (to update field *after* hdr & pkts copied to gcPhys) */
    14621342        AssertMsgReturn(pDescChain->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONET_PKT_HDR_T),
    1463                         ("Desc chain's phys segs have insufficient space for pkt header!\n"),
     1343                        ("Desc chain's first seg has insufficient space for pkt header!\n"),
    14641344                        VERR_INTERNAL_ERROR);
    14651345
     
    14701350        {
    14711351            /* Lead with packet header */
    1472             paSegs[cSegs].cbSeg = sizeof(VIRTIONET_PKT_HDR_T);
    1473             paSegs[cSegs].pvSeg = RTMemAlloc(paSegs[0].cb);
    1474             AssertReturn(paSegs[0].pvSeg, VERR_NO_MEMORY);
    1475 
    1476             gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0]
    1477                 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers);
    1478 
    1479             cSegs++;
     1352            paVirtSegsToGuest[cSegs].cbSeg = sizeof(VIRTIONET_PKT_HDR_T);
     1353            paVirtSegsToGuest[cSegs].pvSeg = RTMemAlloc(sizeof(VIRTIONET_PKT_HDR_T));
     1354            AssertReturn(paVirtSegsToGuest[0].pvSeg, VERR_NO_MEMORY);
     1355
     1356            /* Calculate & cache the field we will need to update later in gcPhys memory */
     1357            gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].gcPhys
     1358                                     + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers);
     1359
     1360            if (cSegs++ >= cSegsAllocated)
     1361            {
     1362                cSegsAllocated <<= 1;
     1363                paVirtSegsToGuest = (PRTSGSEG)RTMemRealloc(paVirtSegsToGuest, sizeof(RTSGSEG) * cSegsAllocated);
     1364                AssertReturn(paVirtSegsToGuest, VERR_NO_MEMORY);
     1365            }
     1366
    14801367            fAddPktHdr = false;
    14811368            cbDescChainLeft -= sizeof(VIRTIONET_PKT_HDR_T);
     
    14831370
    14841371        /* Append remaining Rx pkt or as much current desc chain has room for */
    1485         uint32_t uSize = RT_MIN(cb, cbDescChainLeft);
    1486         paSegs[cSegs].cbSeg = uSize;
    1487         paSegs[cSegs++].pvSeg = ((uint8_t)pvBuf) + uOffset;
    1488         uOffset += uSize;
     1372        uint32_t uboundedSize = RT_MIN(cb, cbDescChainLeft);
     1373        paVirtSegsToGuest[cSegs].cbSeg = uboundedSize;
     1374        paVirtSegsToGuest[cSegs++].pvSeg = ((uint8_t *)pvBuf) + uOffset;
     1375        uOffset += uboundedSize;
    14891376        cDescs++;
    14901377
    1491         virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, RXQIDX(0), pSegsBuf, pDescChain, true);
     1378        RTSgBufInit(pVirtSegBufToGuest, paVirtSegsToGuest, cSegs);
     1379
     1380        virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0),
     1381                             pVirtSegBufToGuest, pDescChain, true);
    14921382
    14931383        if (FEATURE_DISABLED(MRG_RXBUF))
     
    14951385    }
    14961386
    1497     /* Fix up pkt hdr (already in guest phys. memory) with number of descriptors to send */
    1498 
    1499     int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, cDescs, sizeof(cDescs));
    1500     AssertMsgRCReturn(rc, "Failure updating descriptor count in pkt hdr in guest physical memory\n");
    1501 
    1502     virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX(0));
     1387    /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
     1388
     1389    int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs));
     1390    AssertMsgRCReturn(rc,
     1391                      ("Failure updating descriptor count in pkt hdr in guest physical memory\n"),
     1392                      rc);
     1393
     1394    virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX_QPAIR(0));
    15031395
    15041396    for (int i = 0; i < 2; i++)
    1505         RTMemFree(paSegs[i].pvSeg);
    1506 
    1507     RTMemFree(paSegs);
    1508     RTMemFree(pSegsBuf);
     1397        RTMemFree(paVirtSegsToGuest[i].pvSeg);
     1398
     1399    RTMemFree(paVirtSegsToGuest);
     1400    RTMemFree(pVirtSegBufToGuest);
    15091401
    15101402    if (uOffset < cb)
    15111403    {
    1512         Log(("%s virtioNetR3HandleRxPacket: Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));
     1404        LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));
    15131405        return VERR_TOO_MUCH_DATA;
    15141406    }
     
    15201412 * @interface_method_impl{PDMINETWORKDOWN,pfnReceiveGso}
    15211413 */
    1522 static DECLCALLBACK(int) virtioNetR3ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf,
     1414static DECLCALLBACK(int) virtioNetR3NetworkDown_ReceiveGso(PPDMINETWORKDOWN pInterface, const void *pvBuf,
    15231415                                               size_t cb, PCPDMNETWORKGSO pGso)
    15241416{
    1525     PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, PVIRTIONETCC, INetworkDown);
     1417    PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
    15261418    PPDMDEVINS      pDevIns = pThisCC->pDevIns;
    15271419    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     
    15291421    if (pGso)
    15301422    {
    1531         uint32_t uFeatures = pThis->VPCI.uGuestFeatures;
    1532 
    1533         switch (pGso->uType)
     1423        uint32_t uFeatures = pThis->fNegotiatedFeatures;
     1424
     1425        switch (pGso->u8Type)
    15341426        {
    15351427            case PDMNETWORKGSOTYPE_IPV4_TCP:
     
    15491441        if (!uFeatures)
    15501442        {
    1551             Log2Func((GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->uType));
     1443            Log2Func(("GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->u8Type));
    15521444            return VERR_NOT_SUPPORTED;
    15531445        }
     
    15561448    Log2Func(("pvBuf=%p cb=%u pGso=%p\n", INSTANCE(pThis), pvBuf, cb, pGso));
    15571449
    1558     int rc = virtioR3CanReceive(pDevIns, pThis, pThisCC);
     1450    int rc = virtioNetR3IsRxQueuePrimed(pDevIns, pThis);
    15591451    if (RT_FAILURE(rc))
    15601452        return rc;
     
    15641456    if ((   enmVMState != VMSTATE_RUNNING
    15651457         && enmVMState != VMSTATE_RUNNING_LS)
    1566         || !(pThis->virtioNetConfig.uStatus & VIRTIONET_S_LINK_UP))
     1458        || !(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP))
    15671459        return VINF_SUCCESS;
    15681460
    1569     STAM_PROFILE_START(&pThis->StatReceive, a);
    1570     virtioNetR3SetReadLed(&pThisCC, true);
     1461    virtioNetR3SetReadLed(pThisCC, true);
    15711462    if (virtioNetR3AddressFilter(pThis, pvBuf, cb))
    15721463    {
    1573         rc = virtioNetCsRxEnter(pThis, VERR_SEM_BUSY);
    1574         if (RT_SUCCESS(rc))
    1575         {
    1576             rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso);
    1577             STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
    1578             virtioNetCsRxLeave(pThis);
    1579         }
    1580     }
    1581     virtioNetR3SetReadLed(&pThisCC, false);
    1582     STAM_PROFILE_STOP(&pThis->StatReceive, a);
     1464        rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso);
     1465    }
     1466    virtioNetR3SetReadLed(pThisCC, false);
    15831467    return rc;
    15841468}
    15851469
    1586 
    1587 DECLINLINE(uint16_t) virtioNetR3Checkum16(const void *pvBuf, size_t cb)
    1588 {
    1589     uint32_t  chksum = 0;
    1590     uint16_t *pu = (uint16_t *)pvBuf;
    1591 
    1592     while (cb > 1)
    1593     {
    1594         chksum += *pu++;
    1595         cb -= 2;
    1596     }
    1597     if (cb)
    1598         chksum += *(uint8_t*)pu;
    1599     while (chksum >> 16)
    1600         chksum = (chksum >> 16) + (chksum & 0xFFFF);
    1601     return ~chksum;
    1602 }
    1603 
    1604 DECLINLINE(void) virtioNetR3CompleteChecksum(uint8_t *pBuf, size_t cbSize, uint16_t uStart, uint16_t uOffset)
    1605 {
    1606     AssertReturnVoid(uStart < cbSize);
    1607     AssertReturnVoid(uStart + uOffset + sizeof(uint16_t) <= cbSize);
    1608     *(uint16_t *)(pBuf + uStart + uOffset) = virtioNetR3Chksum16(pBuf + uStart, cbSize - uStart);
    1609 }
     1470/**
     1471 * @interface_method_impl{PDMINETWORKDOWN,pfnReceive}
     1472 */
     1473static DECLCALLBACK(int) virtioNetR3NetworkDown_Receive(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)
     1474{
     1475    return virtioNetR3NetworkDown_ReceiveGso(pInterface, pvBuf, cb, NULL);
     1476}
     1477
     1478
    16101479
    16111480/* Read physical bytes from the out segment(s) of descriptor chain */
    1612 static void virtioNetR3PullChain(PVIRTIO_DESC_CHAIN_T pDecChain, void *pv, uint16_t cb)
     1481static void virtioNetR3PullChain(PPDMDEVINS pDevIns, PVIRTIO_DESC_CHAIN_T pDescChain, void *pv, uint16_t cb)
    16131482{
    16141483    uint8_t *pb = (uint8_t *)pv;
    1615     for (size_t cb = RT_MIN(pDescChain->cbPhysSend, sizeof(VIRTIONET_PKT_HDR_T)); cb; )
    1616     {
    1617         size_t cbSeg = cb;
     1484    uint16_t cbMin = RT_MIN(pDescChain->cbPhysSend, cb);
     1485    while (cbMin)
     1486    {
     1487        size_t cbSeg = cbMin;
    16181488        RTGCPHYS GCPhys = virtioCoreSgBufGetNextSegment(pDescChain->pSgPhysSend, &cbSeg);
    16191489        PDMDevHlpPCIPhysRead(pDevIns, GCPhys, pb, cbSeg);
    16201490        pb += cbSeg;
    1621         cb -= cbSeg;
    1622     }
     1491        cbMin -= cbSeg;
     1492    }
     1493    LogFunc(("Pulled %d bytes out of %d bytes requested from descriptor chain\n", cbMin, cb));
    16231494}
    16241495
    16251496
    16261497static uint8_t virtioNetR3CtrlRx(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    1627                                  PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
    1628 {
    1629 #define LOG_VIRTIONET_FLAG(field) LogFunc(("%s = %d\n", #field, pThis->field));
     1498                                 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1499{
     1500
     1501#define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s = %d\n", #fld, pThis->fld))
    16301502
    16311503    LogFunc((""));
     
    16431515        /* fallthrough */
    16441516      case VIRTIONET_CTRL_RX_NOBCAST:
    1645         AssertMsgReturn(fFeatures & VIRTIONET_F_CTRL_RX_EXTRA,
    1646                         ("CTRL "extra" cmd w/o VIRTIONET_F_CTRL_RX_EXTRA feature negotiated - skipping\n"),
     1517        AssertMsgReturn(FEATURE_ENABLED(CTRL_RX_EXTRA),
     1518                        ("CTRL 'extra' cmd w/o VIRTIONET_F_CTRL_RX_EXTRA feature negotiated - skipping\n"),
    16471519                        VIRTIONET_ERROR);
    16481520        /* fall out */
     
    16501522
    16511523    uint8_t fOn, fPromiscChanged = false;
    1652     virtioNetR3PullChain(pDescChain, &fOn, RT_MIN(pDescChain->cbPhysSend, sizeof(fOn)));
     1524    virtioNetR3PullChain(pDevIns, pDescChain, &fOn, RT_MIN(pDescChain->cbPhysSend, sizeof(fOn)));
    16531525
    16541526    switch(pCtrlPktHdr->uCmd)
     
    16571529        pThis->fPromiscuous = !!fOn;
    16581530        fPromiscChanged = true;
    1659         LOG_VIRTIONET_FLAG(fPromiscuous)
     1531        LOG_VIRTIONET_FLAG(fPromiscuous);
    16601532        break;
    16611533      case VIRTIONET_CTRL_RX_ALLMULTI:
     
    16841556    if (pThisCC->pDrv && fPromiscChanged)
    16851557    {
    1686         uint8_t fPromiscuous = pThis->fPromiscuous | pThis->fAllMulticast
     1558        uint8_t fPromiscuous = pThis->fPromiscuous | pThis->fAllMulticast;
    16871559        LogFunc(("Setting promiscuous state to %d\n", fPromiscuous));
    16881560        pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, fPromiscuous);
     
    16931565
    16941566static uint8_t virtioNetR3CtrlMac(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    1695                                   PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
    1696 {
     1567                                  PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1568{
     1569RT_NOREF(pThisCC);
     1570
    16971571#define ASSERT_CTRL_ADDR_SET(v) \
    1698     AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd"), VIRTIONET_ERROR);
     1572    AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_ADDR_SET cmd"), VIRTIONET_ERROR)
    16991573
    17001574#define ASSERT_CTRL_TABLE_SET(v) \
    1701     AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd"), VIRTIONET_ERROR);
    1702 
    1703     int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr);
    1704 
    1705     switch(pCtrlPktHder->uCmd)
     1575    AssertMsgReturn((v), ("DESC chain too small to process CTRL_MAC_TABLE_SET cmd"), VIRTIONET_ERROR)
     1576
     1577    AssertMsgReturn(pDescChain->cbPhysSend >= sizeof(*pCtrlPktHdr),
     1578                   ("insufficient descriptor space for ctrl pkt hdr"),
     1579                   VIRTIONET_ERROR);
     1580
     1581    size_t cbRemaining = pDescChain->cbPhysSend - sizeof(*pCtrlPktHdr);
     1582
     1583    switch(pCtrlPktHdr->uCmd)
    17061584    {
    17071585        case VIRTIONET_CTRL_MAC_ADDR_SET:
     
    17091587            /* Set default Rx filter MAC */
    17101588            ASSERT_CTRL_ADDR_SET(cbRemaining >= sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
    1711             virtioNetR3PullChain(pDescChain, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
     1589            virtioNetR3PullChain(pDevIns, pDescChain, &pThis->rxFilterMacDefault, sizeof(VIRTIONET_CTRL_MAC_TABLE_LEN));
    17121590            break;
    17131591        }
     
    17181596            /* Load unicast MAC filter table */
    17191597            ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs));
    1720             virtioNetR3PullChain(pDescChain, &cMacs, sizeof(cMacs));
     1598            virtioNetR3PullChain(pDevIns, pDescChain, &cMacs, sizeof(cMacs));
    17211599            cbRemaining -= sizeof(cMacs);
    17221600            uint32_t cbMacs = cMacs * sizeof(RTMAC);
    17231601            ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs);
    1724             virtioNetR3PullChain(pDescChain, &pThis->aMacUnicastFilter, cbMacs);
     1602            virtioNetR3PullChain(pDevIns, pDescChain, &pThis->aMacUnicastFilter, cbMacs);
    17251603            cbRemaining -= cbMacs;
    17261604            pThis->cUnicastFilterMacs = cMacs;
     
    17281606            /* Load multicast MAC filter table */
    17291607            ASSERT_CTRL_TABLE_SET(cbRemaining >= sizeof(cMacs));
    1730             virtioNetR3PullChain(pDescChain, &cMacs, sizeof(cMacs));
     1608            virtioNetR3PullChain(pDevIns, pDescChain, &cMacs, sizeof(cMacs));
    17311609            cbRemaining -= sizeof(cMacs);
    17321610            cbMacs = cMacs * sizeof(RTMAC);
    17331611            ASSERT_CTRL_TABLE_SET(cbRemaining >= cbMacs);
    1734             virtioNetR3PullChain(pDescChain, &pThis->aMacMulticastFilter, cbMacs);
     1612            virtioNetR3PullChain(pDevIns, pDescChain, &pThis->aMacMulticastFilter, cbMacs);
    17351613            cbRemaining -= cbMacs;
    17361614            pThis->cMulticastFilterMacs = cMacs;
    17371615
    17381616#ifdef LOG_ENABLED
    1739             LogFunc(("%s: unicast MACs:\n", INSTANCE(pThis))));
    1740             for(unsigned i = 0; i < nMacs; i++)
     1617            LogFunc(("%s: unicast MACs:\n", INSTANCE(pThis)));
     1618            for(unsigned i = 0; i < cMacs; i++)
    17411619                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
    17421620
    1743             LogFunc(("%s: multicast MACs:\n", INSTANCE(pThis))));
    1744             for(unsigned i = 0; i < nMacs; i++)
     1621            LogFunc(("%s: multicast MACs:\n", INSTANCE(pThis)));
     1622            for(unsigned i = 0; i < cMacs; i++)
    17451623                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
    17461624#endif
     
    17521630
    17531631static uint8_t virtioNetR3CtrlVlan(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    1754                                    PVIRTIONET_PKT_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
    1755 {
     1632                                   PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
     1633{
     1634    RT_NOREF(pThisCC);
     1635
    17561636    uint16_t uVlanId;
    1757     int cbRemaining = pDescChain.cbPhysSend - sizeof(*pCtrlPktHdr);
     1637    uint16_t cbRemaining = pDescChain->cbPhysSend - sizeof(*pCtrlPktHdr);
    17581638    AssertMsgReturn(cbRemaining > sizeof(uVlanId),
    17591639        ("DESC chain too small for VIRTIO_NET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR);
    1760     virtioNetR3PullChain(pDescChain, &uVlanId, sizeof(uVlanId));
     1640    virtioNetR3PullChain(pDevIns, pDescChain, &uVlanId, sizeof(uVlanId));
    17611641    AssertMsgReturn(uVlanId > VIRTIONET_MAX_VLAN_ID,
    17621642        ("%s VLAN ID out of range (VLAN ID=%u)\n", INSTANCE(pThis), uVlanId), VIRTIONET_ERROR);
     
    17791659                            PVIRTIO_DESC_CHAIN_T pDescChain)
    17801660{
    1781     PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1782     PVIRTIONETCC    pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    1783 
     1661
     1662#define SIZEOF_SEND(descChain, ctrlHdr) RT_MIN(descChain->cbPhysSend, sizeof(ctrlHdr))
    17841663
    17851664    if (pDescChain->cbPhysSend < 2)
     
    17971676     * Allocate buffer and read in the control command
    17981677     */
    1799     PVIRTIONET_PKT_HDR_T pCtrlPktHdr = (PVIRTIONET_PKT_HDR_T)RTMemAllocZ(sizeof(VIRTIONET_PKT_HDR_T));
    1800     AssertPtrReturn(pCtrlPktHdr, VERR_NO_MEMORY /*ignored*/);
    1801 
    1802     AssertMsgReturnVoid(pDescChain >= sizeof(*pCtrlPktHdr), ("DESC chain too small for CTRL pkt header"));
    1803     virtioNetR3PullChain(pDescChain, pCtrlPktHdr, SIZEOF_SEND(pDescChain, VIRTIONET_PKT_HDR_T));
     1678    PVIRTIONET_CTRL_HDR_T pCtrlPktHdr = (PVIRTIONET_CTRL_HDR_T)RTMemAllocZ(sizeof(VIRTIONET_CTRL_HDR_T));
     1679
     1680    AssertPtrReturnVoid(pCtrlPktHdr);
     1681
     1682    AssertMsgReturnVoid(pDescChain->cbPhysSend >= sizeof(*pCtrlPktHdr),
     1683                        ("DESC chain too small for CTRL pkt header"));
     1684
     1685    virtioNetR3PullChain(pDevIns, pDescChain, pCtrlPktHdr, SIZEOF_SEND(pDescChain, VIRTIONET_CTRL_HDR_T));
    18041686
    18051687    uint8_t uAck;
     
    18191701    }
    18201702
     1703    int cSegs = 2;
     1704
    18211705    /* Return CTRL packet Ack byte (result code) to guest driver */
    1822     PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * 2);
    1823     AssertReturn(paSegs, VERR_NO_MEMORY);
     1706    PRTSGSEG paSegs = (PRTSGSEG)RTMemAllocZ(sizeof(RTSGSEG) * cSegs);
     1707    AssertMsgReturnVoid(paSegs, ("Out of memory"));
    18241708
    18251709    RTSGSEG aSegs[] = { { &uAck, sizeof(uAck) } };
     
    18271711
    18281712    PRTSGBUF pSegBuf = (PRTSGBUF)RTMemAllocZ(sizeof(RTSGBUF));
    1829     AssertReturn(pSegBuf, VERR_NO_MEMORY);
     1713    AssertMsgReturnVoid(pSegBuf, ("Out of memory"));
     1714
    18301715
    18311716    /* Copy segment data to malloc'd memory to avoid stack out-of-scope errors sanitizer doesn't detect */
     
    18341719        void *pv = paSegs[i].pvSeg;
    18351720        paSegs[i].pvSeg = RTMemAlloc(paSegs[i].cbSeg);
    1836         AssertReturn(paSegs[i].pvSeg, VERR_NO_MEMORY);
     1721        AssertMsgReturnVoid(paSegs[i].pvSeg, ("Out of memory"));
    18371722        memcpy(paSegs[i].pvSeg, pv, paSegs[i].cbSeg);
    18381723    }
     
    18401725    RTSgBufInit(pSegBuf, paSegs, cSegs);
    18411726
    1842     virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, pSegBuf, pDescChain, true);
    1843     virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx);
     1727    virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pSegBuf, pDescChain, true);
     1728    virtioCoreQueueSync(pDevIns, &pThis->Virtio, CTRLQIDX);
    18441729
    18451730    for (int i = 0; i < cSegs; i++)
     
    18501735
    18511736    LogFunc(("Processed ctrl message class/cmd/subcmd = %u/%u/%u. Ack=%u.\n",
    1852               pCtrlPktHdr.uClass, pCtrlPktHdr.uCmd, pCtrlPktHdr.uCmdSpecific, uAck);
     1737              pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd, pCtrlPktHdr->uCmdSpecific, uAck));
    18531738
    18541739}
     
    18611746
    18621747    Log4(("virtio-net: header flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x cb=%x\n",
    1863           pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, pPktHdr->uGSOSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax));
     1748          pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen,
     1749          pPktHdr->uGsoSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbMax));
    18641750
    18651751    if (pPktHdr->uGsoType)
     
    18691755        /* Segmentation offloading cannot be done without checksumming, and we do not support ECN */
    18701756        if (  RT_UNLIKELY(!(pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM))
    1871             | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN)))
     1757            | RT_UNLIKELY(pPktHdr->uGsoType & VIRTIONET_HDR_GSO_ECN))
    18721758                return false;
    18731759
     
    18851771        }
    18861772        /* Header + MSS must not exceed the packet size. */
    1887         if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGSOSize > cbMax))
     1773        if (RT_UNLIKELY(uMinHdrSize + pPktHdr->uChksumStart + pPktHdr->uGsoSize > cbMax))
    18881774            return false;
    18891775    }
     
    18921778         && sizeof(uint16_t) + pPktHdr->uChksumStart + pPktHdr->uChksumOffset > cbMax)
    18931779               return false;
    1894     Log4func(("returning true\n"));
     1780    Log4Func(("returning true\n"));
    18951781    return true;
    18961782}
    18971783
    18981784static int virtioNetR3TransmitFrame(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMSCATTERGATHER pSgBuf,
    1899                                PPDMNETWORKGSO pGso, PVNETHDR pHdr)
     1785                               PPDMNETWORKGSO pGso, PVIRTIONET_PKT_HDR_T pPktHdr)
    19001786{
    19011787    virtioNetR3PacketDump(pThis, (uint8_t *)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, "--> Outgoing");
     
    19071793         * it gets filled out by different versions of kernels.
    19081794         */
    1909         //if (pGso->cbHdrs < pHdr->uCSumStart + pHdr->uCSumOffset + 2)
     1795        //if (pGso->cbHdrs < pPktHdr->uCSumStart + pPktHdr->uCSumOffset + 2)
    19101796        {
    19111797            Log4Func(("%s: HdrLen before adjustment %d.\n",
     
    19151801                case PDMNETWORKGSOTYPE_IPV4_TCP:
    19161802                case PDMNETWORKGSOTYPE_IPV6_TCP:
    1917                     pGso->cbHdrsTotal = pHdr->uChkumStart +
    1918                         ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pHdr->uChkumStart))->th_off * 4;
     1803                    pGso->cbHdrsTotal = pPktHdr->uChksumStart +
     1804                        ((PRTNETTCP)(((uint8_t*)pSgBuf->aSegs[0].pvSeg) + pPktHdr->uChksumStart))->th_off * 4;
    19191805                    pGso->cbHdrsSeg   = pGso->cbHdrsTotal;
    19201806                    break;
    19211807                case PDMNETWORKGSOTYPE_IPV4_UDP:
    1922                     pGso->cbHdrsTotal = (uint8_t)(pHdr->uCSumStart + sizeof(RTNETUDP));
    1923                     pGso->cbHdrsSeg   = pHdr->u16CSumStart;
     1808                    pGso->cbHdrsTotal = (uint8_t)(pPktHdr->uChksumStart + sizeof(RTNETUDP));
     1809                    pGso->cbHdrsSeg = pPktHdr->uChksumStart;
    19241810                    break;
    19251811            }
     
    19271813            ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsTotal = pGso->cbHdrsTotal;
    19281814            ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg   = pGso->cbHdrsSeg;
    1929             Log4(("%s vnetR3TransmitPendingPackets: adjusted HdrLen to %d.\n",
     1815            Log4Func(("%s: adjusted HdrLen to %d.\n",
    19301816                  INSTANCE(pThis), pGso->cbHdrsTotal));
    19311817        }
     
    19331819                  INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg,
    19341820                  pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
    1935         STAM_REL_COUNTER_INC(&pThis->StatTransmitGSO);
    1936     }
    1937     else if (pHdr->u8Flags & VNETHDR_F_NEEDS_CSUM)
    1938     {
    1939         STAM_REL_COUNTER_INC(&pThis->StatTransmitCSum);
     1821    }
     1822    else if (pPktHdr->uFlags & VIRTIONET_HDR_F_NEEDS_CSUM)
     1823    {
    19401824        /*
    19411825         * This is not GSO frame but checksum offloading is requested.
    19421826         */
    19431827        virtioNetR3CompleteChecksum((uint8_t*)pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed,
    1944                              pHdr->uChkumStart, pHdr->uCSumOffset);
     1828                             pPktHdr->uChksumStart, pPktHdr->uChksumOffset);
    19451829    }
    19461830
     
    19481832}
    19491833
    1950 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVNETSTATE pThis, PVNETSTATECC pThisCC,
     1834static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    19511835                                         uint16_t qIdx, bool fOnWorkerThread)
    19521836{
    1953     PVIRTIOCORE pVirtio = pThis->pVirtio;
     1837    PVIRTIOCORE pVirtio = &pThis->Virtio;
    19541838
    19551839    /*
     
    19611845        return;
    19621846
    1963     if (!fVirtioReady)
     1847    if (!pThis->fVirtioReady)
    19641848    {
    19651849        LogFunc(("%s Ignoring transmit requests. VirtIO not ready (status=0x%x).\n",
     
    19881872    unsigned int cbPktHdr = sizeof(VIRTIONET_PKT_HDR_T);
    19891873
    1990     Log3func(("%s: About to transmit %d pending packets\n",
    1991               INSTANCE(pThis), virtioCoreR3QueuePendingCount(pVirtio->pDevIndx, pVirtio, TXQIDX(0));
    1992 
    1993     virtioNetR3SetWriteLed(&pThisCC, true);
     1874    Log3Func(("%s: About to transmit %d pending packets\n", INSTANCE(pThis),
     1875              virtioCoreR3QueuePendingCount(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0))));
     1876
     1877    virtioNetR3SetWriteLed(pThisCC, true);
     1878
    19941879
    19951880    PVIRTIO_DESC_CHAIN_T pDescChain;
    1996     while (virtioCoreR3QueuePeek(pVirtio->pDevIns, pVirtio, TXQIDX(0), &pDescChain) {
    1997     {
    1998         unsigned uOffset = 0;
    1999         uint32_t cVirtioSegs = pDescChain->pSgPhysSend->cSegs;
    2000         PVIRTIOSGSEG paVirtioSegs = pDescChain->pSgPhysSend->paSegs;
    2001 
    2002         if (cVirtioSegs < 2 || paVirtioSegs[0].cbSeg != cbPktHdr)
     1881    while (virtioCoreR3QueuePeek(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0), &pDescChain))
     1882    {
     1883        uint32_t cSegsFromGuest = pDescChain->pSgPhysSend->cSegs;
     1884        PVIRTIOSGSEG paSegsFromGuest = pDescChain->pSgPhysSend->paSegs;
     1885
     1886        Log6Func(("fetched descriptor chain from %s\n", VIRTQNAME(qIdx)));
     1887
     1888        if (cSegsFromGuest < 2 || paSegsFromGuest[0].cbSeg != cbPktHdr)
    20031889        {
    20041890            /* This check could be made more complex, because in theory (but not likely nor
    20051891             * seen in practice) the first segment could contain header and data. */
    20061892            LogFunc(("%s: The first segment is not the header! (%u < 2 || %u != %u).\n",
    2007                  INSTANCE(pThis), cVirtioSegs, paVirtioSegs[0].cbSeg, cbPktHdr));
     1893                 INSTANCE(pThis), cSegsFromGuest, paSegsFromGuest[0].cbSeg, cbPktHdr));
    20081894            break;
    20091895        }
     
    20131899
    20141900        /* Compute total frame size. */
    2015         for (unsigned i = 1; i < cVirtioSegs && uSize < VIRTIONET_MAX_FRAME_SIZE; i++)
    2016             uSize +=  paVirtioSegs[i].cbSeg;
    2017 
    2018         Log5func(("%s: complete frame is %u bytes.\n", INSTANCE(pThis), uSize));
     1901        for (unsigned i = 1; i < cSegsFromGuest && uSize < VIRTIONET_MAX_FRAME_SIZE; i++)
     1902            uSize +=  paSegsFromGuest[i].cbSeg;
     1903
     1904        Log5Func(("%s: complete frame is %u bytes.\n", INSTANCE(pThis), uSize));
    20191905        Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE);
    20201906
     
    20231909            uSize = VIRTIONET_MAX_FRAME_SIZE;
    20241910
    2025         if (pThisCC->pDrv && virtioNetR3ReadHeader(pDevIns, paVirtioSegs[0].gcPhys, &PktHdr, uSize))
     1911        if (pThisCC->pDrv && virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].gcPhys, &PktHdr, uSize))
    20261912        {
    20271913            PDMNETWORKGSO Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);
    20281914
    20291915            /** @todo Optimize away the extra copying! (lazy bird) */
    2030             PPDMSCATTERGATHER pPdmSgBuf;
    2031             int rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pPdmSgBuf);
     1916            PPDMSCATTERGATHER pSgBufToPdmLeafDevice;
     1917            int rc = pThisCC->pDrv->pfnAllocBuf(pThisCC->pDrv, uSize, pGso, &pSgBufToPdmLeafDevice);
    20321918            if (RT_SUCCESS(rc))
    20331919            {
    2034                 pPdmSgBuf->cbUsed = uSize;
     1920                pSgBufToPdmLeafDevice->cbUsed = uSize;
    20351921
    20361922                /* Assemble a complete frame. */
    2037                 for (unsigned i = 1; i < cVirtioSegs && uSize > 0; i++)
     1923                for (unsigned i = 1; i < cSegsFromGuest && uSize > 0; i++)
    20381924                {
    20391925                    unsigned uOffset;
    2040                     unsigned cbSeg = RT_MIN(uSize, paVirtioSegs[i].cbSeg);
    2041 
    2042                     PDMDevHlpPCIPhysRead(pDevIns, paVirtioSegs[i].gcPhys;
    2043                                          ((uint8_t *)pPdmSgBuf->aSegs[0].pvSeg) + uOffset,
     1926                    unsigned cbSeg = RT_MIN(uSize, paSegsFromGuest[i].cbSeg);
     1927
     1928                    PDMDevHlpPCIPhysRead(pDevIns, paSegsFromGuest[i].gcPhys,
     1929                                         ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset,
    20441930                                         cbSeg);
    20451931                    uOffset += cbSeg;
    20461932                    uSize -= cbSeg;
    20471933                }
    2048                 rc = virtioNetR3TransmitFrame(pThis, pThisCC, pPdmSgBuf, pGso, &PktHdr);
     1934                rc = virtioNetR3TransmitFrame(pThis, pThisCC, pSgBufToPdmLeafDevice, pGso, &PktHdr);
    20491935            }
    20501936            else
    20511937            {
    2052                 Log4func(("Failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc));
     1938                Log4Func(("Failed to allocate SG buffer: size=%u rc=%Rrc\n", uSize, rc));
    20531939                /* Stop trying to fetch TX descriptors until we get more bandwidth. */
    20541940                break;
     
    20571943
    20581944        /* Remove this descriptor chain from the available ring */
    2059         virtioCoreR3QueueSkip(pVirtio, TXQIDX(0));
     1945        virtioCoreR3QueueSkip(pVirtio, TXQIDX_QPAIR(0));
    20601946
    20611947        /* No data to return to guest, but call is needed put elem (e.g. desc chain) on used ring */
    2062         virtioCoreR3QueuePut(pVirtio->pDevIns, pVirtio, TXQIDX(0), NULL, pDescChain, false);
    2063 
    2064         virtioCoreQueueSync(pVirtio->pDevIns, pVirtio, TXQIDX(0));
     1948        virtioCoreR3QueuePut(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0), NULL, pDescChain, false);
     1949
     1950        virtioCoreQueueSync(pVirtio->pDevIns, pVirtio, TXQIDX_QPAIR(0));
     1951
    20651952    }
    20661953    virtioNetR3SetWriteLed(pThisCC, false);
     
    20741961 * @interface_method_impl{PDMINETWORKDOWN,pfnXmitPending}
    20751962 */
    2076 static DECLCALLBACK(void) vnetR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
     1963static DECLCALLBACK(void) virtioNetR3NetworkDown_XmitPending(PPDMINETWORKDOWN pInterface)
    20771964{
    20781965    PVIRTIONETCC    pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkDown);
    20791966    PPDMDEVINS      pDevIns = pThisCC->pDevIns;
    20801967    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
    2081     vnetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/);
    2082 }
    2083 
    2084 # ifdef VNET_TX_DELAY
    2085 
    2086 /**
    2087  * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue}
    2088  */
    2089 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, PVQUEUE pQueue)
    2090 {
    2091     PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    2092     PVIRTIONETCC    pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    2093 
    2094     if (PDMDevHlpTimerIsActive(pDevIns, pThis->hTxTimer))
    2095     {
    2096         PDMDevHlpTimerStop(pDevIns, pThis->hTxTimer);
    2097         Log3Func(("%: Got kicked with notification disabled, re-enable notification and flush TX queue\n", INSTANCE(pThis)));
    2098         virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/);
    2099         if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY)))
    2100             LogRelFunc(("Failed to enter critical section!/n"));
    2101         else
     1968    virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX_QPAIR(0), false /*fOnWorkerThread*/);
     1969}
     1970
     1971/**
     1972 * @callback_method_impl{VIRTIOCORER3,pfnQueueNotified}
     1973 */
     1974static DECLCALLBACK(void) virtioNetR3QueueNotified(PVIRTIOCORE pVirtio, PVIRTIOCORECC pVirtioCC, uint16_t qIdx)
     1975{
     1976    PVIRTIONET         pThis     = RT_FROM_MEMBER(pVirtio, VIRTIONET, Virtio);
     1977    PVIRTIONETCC       pThisCC   = RT_FROM_MEMBER(pVirtioCC, VIRTIONETCC, Virtio);
     1978    PPDMDEVINS         pDevIns   = pThisCC->pDevIns;
     1979    PVIRTIONETWORKER   pWorker   = &pThis->aWorkers[qIdx];
     1980    PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[qIdx];
     1981    AssertReturnVoid(qIdx < pThis->cVirtQueues);
     1982
     1983#ifdef LOG_ENABLED
     1984    RTLogFlush(NULL);
     1985#endif
     1986
     1987    Log6Func(("%s has available buffers\n", VIRTQNAME(qIdx)));
     1988
     1989    if (IS_RX_QUEUE(qIdx))
     1990    {
     1991        LogFunc(("%s Receive buffers has been added, waking up receive thread.\n",
     1992            INSTANCE(pThis)));
     1993        virtioNetR3WakeupRxBufWaiter(pDevIns);
     1994    }
     1995    else
     1996    {
     1997        /* Wake queue's worker thread up if sleeping */
     1998        if (!ASMAtomicXchgBool(&pWorkerR3->fNotified, true))
    21021999        {
    2103             virtioCoreQueueSetNotify(&pThis->Virtio,  TXQIDX(0), true);
    2104             virtioNetR3CsLeave(pDevIns, pThis);
     2000            if (ASMAtomicReadBool(&pWorkerR3->fSleeping))
     2001            {
     2002                Log6Func(("waking %s worker.\n", VIRTQNAME(qIdx)));
     2003                int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
     2004                AssertRC(rc);
     2005            }
    21052006        }
    21062007    }
    2107     else
    2108     {
    2109         if (RT_FAILURE(virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY)))
    2110             LogRelFunc(("Failed to enter critical section!/n"));
    2111         else
    2112         {
    2113             virtioCoreQueueSetNotify(&pThis->Virtio,  TXQIDX(0), false);
    2114             PDMDevHlpTimerSetMicro(pDevIns, pThis->hTxTimer, VNET_TX_DELAY);
    2115             pThis->u64NanoTS = RTTimeNanoTS();
    2116             virtioNetR3CsLeave(pDevIns, pThis);
    2117         }
    2118     }
    2119 }
    2120 
    2121 /**
    2122  * @callback_method_impl{FNTMTIMERDEV, Transmit Delay Timer handler.}
    2123  */
    2124 static DECLCALLBACK(void) virtioNetR3TxTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
    2125 {
    2126     PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    2127     PVIRTIONETCC    pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    2128     RT_NOREF(pTimer, pvUser);
    2129 
    2130     uint32_t u32MicroDiff = (uint32_t)((RTTimeNanoTS() - pThis->u64NanoTS) / 1000);
    2131     if (u32MicroDiff < pThis->u32MinDiff)
    2132         pThis->u32MinDiff = u32MicroDiff;
    2133     if (u32MicroDiff > pThis->u32MaxDiff)
    2134         pThis->u32MaxDiff = u32MicroDiff;
    2135     pThis->u32AvgDiff = (pThis->u32AvgDiff * pThis->u32i + u32MicroDiff) / (pThis->u32i + 1);
    2136     pThis->u32i++;
    2137     Log3Func(("Expired, diff %9d usec, avg %9d usec, min %9d usec, max %9d usec\n",
    2138           u32MicroDiff, pThis->u32AvgDiff, pThis->u32MinDiff, pThis->u32MaxDiff));
    2139 
    2140 //    Log3Func(("%s Expired\n", INSTANCE(pThis)));
    2141     virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/);
    2142     if (RT_FAILURE(virtioNettR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY)))
    2143     {
    2144         LogRelFunc(("Failed to enter critical section!/n"));
    2145         return;
    2146     }
    2147     virtioCoreQueueSetNotify(&pThis->Virtio,  TXQIDX(0), true);
    2148     virtioNetR3CsLeave(pDevIns, pThis);
    2149 }
    2150 
    2151 DECLINLINE(int) virtioNetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    2152 {
    2153     RT_NOREF(pDevIns, pThis, pThisCC);
    2154     return VINF_SUCCESS;
    2155 }
    2156 
    2157 DECLINLINE(void) virtioNetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    2158 {
    2159     RT_NOREF(pDevIns, pThis, pThisCC);
    2160 }
    2161 
    2162 # else /* !VNET_TX_DELAY */
    2163 
    2164 /**
    2165  * @callback_method_impl{FNPDMTHREADDEV}
    2166  */
    2167 static DECLCALLBACK(int) vnetR3TxThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2168 {
    2169     PVNETSTATE      pThis   = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);
    2170     PVNETSTATECC    pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVNETSTATECC);
    2171 
    2172     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    2173         return VINF_SUCCESS;
    2174 
    2175     int rc = VINF_SUCCESS;
    2176     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    2177     {
    2178         rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hTxEvent, RT_INDEFINITE_WAIT);
    2179         if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
    2180             break;
    2181         while (true)
    2182         {
    2183             virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/); /// @todo shouldn't it be true instead?
    2184             LogFunc(("Enable kicking and get to sleep\n"));
    2185             virtioCoreQueueSetNotify(&pThis->Virtio,  TXQIDX(0), true);
    2186             if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, TXQIDX(0)))
    2187                 break;
    2188             virtioCoreQueueSetNotify(&pThis->Virtio, TXQIDX(0), false);
    2189         }
    2190     }
    2191 
    2192     return rc;
    2193 }
    2194 
    2195 /**
    2196  * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
    2197  */
    2198 static DECLCALLBACK(int) virtioNetR3TxThreadWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2199 {
    2200     PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);
    2201     RT_NOREF(pThread);
    2202     return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent);
    2203 }
    2204 
    2205 static int vnetR3CreateTxThreadAndEvent(PPDMDEVINS pDevIns, PVNETSTATE pThis, PVNETSTATECC pThisCC)
    2206 {
    2207     int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hTxEvent);
    2208     if (RT_SUCCESS(rc))
    2209     {
    2210         rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pTxThread, NULL, vnetR3TxThread,
    2211                                    vnetR3TxThreadWakeUp, 0, RTTHREADTYPE_IO, INSTANCE(pThis));
    2212         if (RT_FAILURE(rc))
    2213             PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create worker thread %s"), INSTANCE(pThis));
    2214     }
    2215     else
    2216         PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("VNET: Failed to create SUP event semaphore"));
    2217     return rc;
    2218 }
    2219 
    2220 static void vnetR3DestroyTxThreadAndEvent(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    2221 {
    2222     if (pThisCC->pTxThread)
    2223     {
    2224         /* Destroy the thread. */
    2225         int rcThread;
    2226         int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->pTxThread, &rcThread);
    2227         if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
    2228             AssertMsgFailed(("%s Failed to destroy async IO thread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
    2229         pThisCC->pTxThread = NULL;
    2230     }
    2231 
    2232     if (pThis->hTxEvent != NIL_SUPSEMEVENT)
    2233     {
    2234         PDMDevHlpSUPSemEventClose(pDevIns, pThis->hTxEvent);
    2235         pThis->hTxEvent = NIL_SUPSEMEVENT;
    2236     }
    2237 }
    2238 
    2239 /**
    2240  * @callback_method_impl{FNVPCIQUEUECALLBACK, The TX queue}
    2241  */
    2242 static DECLCALLBACK(void) virtioNetR3QueueTransmit(PPDMDEVINS pDevIns, uint16_t qIdx)
    2243 {
    2244     PVNETSTATE pThis = PDMDEVINS_2_DATA(pDevIns, PVNETSTATE);
    2245 
    2246     LogFunc(("Disable kicking and wake up TX thread\n"));
    2247     virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false);
    2248     int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hTxEvent);
    2249     AssertRC(rc);
    2250 }
    2251 
    2252 # endif /* !VNET_TX_DELAY */
    2253 static void virtioNetR3Transmit(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)
    2254 {
    2255     RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain);
    2256 }
    2257  static void virtioNetR3Receive(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)
    2258 {
    2259     RT_NOREF5(pDevIns, pThis, pThisCC, qIdx, pDescChain);
    2260 }
    2261 
    2262 /**
    2263  * @callback_method_impl{FNPDMTHREADWAKEUPDEV}
    2264  */
    2265 static DECLCALLBACK(int) virtioNetR3WorkerWakeUp(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2266 {
    2267     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    2268     return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[(uintptr_t)pThread->pvUser].hEvtProcess);
    22692008}
    22702009
     
    22852024    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    22862025    {
     2026
     2027        virtioCoreQueueSetNotify(&pThis->Virtio,  qIdx, true);
     2028
    22872029        if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, qIdx))
    22882030        {
     
    22992041                    return VINF_SUCCESS;
    23002042                if (rc == VERR_INTERRUPTED)
     2043                {
     2044                    virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false);
    23012045                    continue;
     2046                }
    23022047                Log6Func(("%s worker woken\n", VIRTQNAME(qIdx)));
    23032048                ASMAtomicWriteBool(&pWorkerR3->fNotified, false);
     
    23062051        }
    23072052
     2053        virtioCoreQueueSetNotify(&pThis->Virtio, qIdx, false);
     2054
    23082055        if (!pThis->afQueueAttached[qIdx])
    23092056        {
     
    23112058            break;
    23122059        }
     2060
     2061        /* Dispatch to the handler for the queue this worker is set up to drive */
     2062
    23132063        if (!pThisCC->fQuiescing)
    23142064        {
    2315              Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME(qIdx)));
    2316              PVIRTIO_DESC_CHAIN_T pDescChain;
    2317              int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, qIdx, &pDescChain, true);
    2318              if (rc == VERR_NOT_AVAILABLE)
     2065             if (IS_CTRL_QUEUE(qIdx))
    23192066             {
    2320                 Log6Func(("Nothing found in %s\n", VIRTQNAME(qIdx)));
    2321                 continue;
     2067                 Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME(qIdx)));
     2068                 PVIRTIO_DESC_CHAIN_T pDescChain;
     2069                 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, qIdx, &pDescChain, true);
     2070                 if (rc == VERR_NOT_AVAILABLE)
     2071                 {
     2072                    Log6Func(("Nothing found in %s\n", VIRTQNAME(qIdx)));
     2073                    continue;
     2074                 }
     2075                 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain);
    23222076             }
    2323 
    2324              AssertRC(rc);
    2325              if (qIdx == CTRLQIDX)
    2326                  virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain);
    2327              else if (qIdx & 1)
    2328                  virtioNetR3Transmit(pDevIns, pThis, pThisCC, qIdx, pDescChain);
    2329              else
    2330                  virtioNetR3Receive(pDevIns, pThis, pThisCC, qIdx, pDescChain);
     2077             else if (IS_TX_QUEUE(qIdx))
     2078             {
     2079                 Log6Func(("Notified of data to transmit\n"));
     2080                 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC,
     2081                                                   qIdx, true /* fOnWorkerThread */);
     2082             }
     2083             /* Rx queues aren't handled by our worker threads. Instead, the PDM network
     2084              * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback,
     2085              * which waits until notified directly by virtioNetR3QueueNotified()
     2086              * that guest IN buffers have been added to receive virt queue. */
    23312087        }
    23322088    }
     
    23342090}
    23352091
    2336 #ifdef IN_RING3
    2337 
    2338 /** Returns true if large packets are written into several RX buffers. */
    2339 DECLINLINE(bool) virtioNetR3MergeableRxBuffers(PVIRTIONET pThis)
    2340 {
    2341     return !!(pThis->fFeatures & VIRTIONET_F_MRG_RXBUF);
    2342 }
    2343 
    23442092DECLINLINE(int) virtioNetR3CsEnter(PPDMDEVINS pDevIns, PVIRTIONET pThis, int rcBusy)
    23452093{
     2094    RT_NOREF(pDevIns, pThis, rcBusy);
    23462095    /* Original DevVirtioNet uses CS in attach/detach/link-up timer/tx timer/transmit */
    2347     LogFunc("CS unimplemented. What does the critical section protect in orig driver??"));
     2096    LogFunc(("CS unimplemented. What does the critical section protect in orig driver??"));
     2097    return VINF_SUCCESS;
    23482098}
    23492099
    23502100DECLINLINE(void) virtioNetR3CsLeave(PPDMDEVINS pDevIns, PVIRTIONET pThis)
    23512101{
    2352     LogFunc("CS unimplemented. What does the critical section protect in orig driver??"));
    2353 }
     2102    RT_NOREF(pDevIns, pThis);
     2103    LogFunc(("CS unimplemented. What does the critical section protect in orig driver??"));
     2104}
     2105
     2106
     2107/**
     2108 * @callback_method_impl{FNTMTIMERDEV, Link Up Timer handler.}
     2109 */
     2110static DECLCALLBACK(void) virtioNetR3LinkUpTimer(PPDMDEVINS pDevIns, PTMTIMER pTimer, void *pvUser)
     2111{
     2112    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2113    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     2114    RT_NOREF(pTimer, pvUser);
     2115
     2116    int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY);
     2117    AssertRCReturnVoid(rc);
     2118
     2119    SET_LINK_UP(pThis);
     2120
     2121    virtioNetR3WakeupRxBufWaiter(pDevIns);
     2122
     2123    virtioNetR3CsLeave(pDevIns, pThis);
     2124
     2125    LogFunc(("%s: Link is up\n", INSTANCE(pThis)));
     2126    if (pThisCC->pDrv)
     2127        pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, PDMNETWORKLINKSTATE_UP);
     2128}
     2129
     2130/**
     2131 * Takes down the link temporarily if it's current status is up.
     2132 *
     2133 * This is used during restore and when replumbing the network link.
     2134 *
     2135 * The temporary link outage is supposed to indicate to the OS that all network
     2136 * connections have been lost and that it for instance is appropriate to
     2137 * renegotiate any DHCP lease.
     2138 *
     2139 * @param   pDevIns     The device instance.
     2140 * @param   pThis       The virtio-net shared instance data.
     2141 * @param   pThisCC     The virtio-net ring-3 instance data.
     2142 */
     2143static void virtioNetR3TempLinkDown(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
     2144{
     2145    if (IS_LINK_UP(pThis))
     2146    {
     2147        SET_LINK_DOWN(pThis);
     2148
     2149        /* Restore the link back in 5 seconds. */
     2150        int rc = PDMDevHlpTimerSetMillies(pDevIns, pThisCC->hLinkUpTimer, pThis->cMsLinkUpDelay);
     2151        AssertRC(rc);
     2152
     2153        LogFunc(("%s: Link is down temporarily\n", INSTANCE(pThis)));
     2154    }
     2155}
     2156
     2157/**
     2158 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
     2159 */
     2160static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface)
     2161{
     2162    PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig);
     2163    PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
     2164
     2165    return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN;
     2166}
     2167
     2168/**
     2169 * @interface_method_impl{PDMINETWORKCONFIG,pfnSetLinkState}
     2170 */
     2171static DECLCALLBACK(int) virtioNetR3NetworkConfig_SetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
     2172{
     2173    PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig);
     2174    PPDMDEVINS   pDevIns = pThisCC->pDevIns;
     2175    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2176
     2177    bool fOldUp = !!(pThis->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP);
     2178    bool fNewUp = enmState == PDMNETWORKLINKSTATE_UP;
     2179
     2180    Log(("%s virtioNetR3NetworkConfig_SetLinkState: enmState=%d\n", INSTANCE(pThis), enmState));
     2181    if (enmState == PDMNETWORKLINKSTATE_DOWN_RESUME)
     2182    {
     2183        if (fOldUp)
     2184        {
     2185            /*
     2186             * We bother to bring the link down only if it was up previously. The UP link state
     2187             * notification will be sent when the link actually goes up in virtioNetR3LinkUpTimer().
     2188             */
     2189            virtioNetR3TempLinkDown(pDevIns, pThis, pThisCC);
     2190            if (pThisCC->pDrv)
     2191                pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState);
     2192        }
     2193    }
     2194    else if (fNewUp != fOldUp)
     2195    {
     2196        if (fNewUp)
     2197        {
     2198            Log(("%s Link is up\n", INSTANCE(pThis)));
     2199            pThis->fCableConnected = true;
     2200            pThis->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP;
     2201            virtioCoreNotifyConfigChanged(&pThis->Virtio);
     2202        }
     2203        else
     2204        {
     2205            /* The link was brought down explicitly, make sure it won't come up by timer.  */
     2206            PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer);
     2207            Log(("%s Link is down\n", INSTANCE(pThis)));
     2208            pThis->fCableConnected = false;
     2209            pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP;
     2210            virtioCoreNotifyConfigChanged(&pThis->Virtio);
     2211        }
     2212        if (pThisCC->pDrv)
     2213            pThisCC->pDrv->pfnNotifyLinkChanged(pThisCC->pDrv, enmState);
     2214    }
     2215    return VINF_SUCCESS;
     2216}
     2217
    23542218
    23552219/**
     
    23682232    {
    23692233        LogFunc(("VirtIO ready\n-----------------------------------------------------------------------------------------\n"));
    2370         uint64_t fFeatures   = virtioCoreGetNegotiatedFeatures(&pThis->Virtio);
     2234//        uint64_t fFeatures   = virtioCoreGetNegotiatedFeatures(pThis->Virtio);
    23712235        pThis->fResetting    = false;
    23722236        pThisCC->fQuiescing  = false;
     
    23792243        LogFunc(("VirtIO is resetting\n"));
    23802244
    2381         pThis->virtioNetConfig.status = pThis->fCableConnected ? VIRTIONET_S_LINK_UP : 0;
     2245        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
    23822246        LogFunc(("%s Link is %s\n", INSTANCE(pThis), pThis->fCableConnected ? "up" : "down"));
    23832247
     
    23852249        pThis->fAllMulticast = false;
    23862250        pThis->fAllUnicast   = false;
    2387         pThis->fNoMulticat   = false;
     2251        pThis->fNoMulticast  = false;
    23882252        pThis->fNoUnicast    = false;
    23892253        pThis->fNoBroadcast  = false;
     
    24122276static DECLCALLBACK(void) virtioNetR3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
    24132277{
    2414     PVIRTIONET       pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    2415     PVIRTIONETCC     pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     2278    RT_NOREF(fFlags);
     2279
     2280    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2281    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    24162282
    24172283    LogFunc((""));
     
    24192285
    24202286    int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY);
    2421     AssertMsgRCReturn(rc, ("Failed to enter critical section"), rc);
     2287    AssertMsgRCReturnVoid(rc, ("Failed to enter critical section"));
    24222288
    24232289    /*
     
    24782344}
    24792345
    2480 /**
    2481  * Turns on/off the write status LED.
    2482  *
    2483  * @returns VBox status code.
    2484  * @param   pThis          Pointer to the device state structure.
    2485  * @param   fOn            New LED state.
    2486  */
    2487 void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn)
    2488 {
    2489     Log6Func(("%s\n", fOn ? "on" : "off"));
    2490     if (fOn)
    2491         pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1;
    2492     else
    2493         pThisR3->led.Actual.s.fWriting = fOn;
    2494 }
    2495 
    2496 /**
    2497  * Turns on/off the read status LED.
    2498  *
    2499  * @returns VBox status code.
    2500  * @param   pThis          Pointer to the device state structure.
    2501  * @param   fOn             New LED state.
    2502  */
    2503 void virtioNetR3SetReadLed(PVIRTIONETR3 pThisR3, bool fOn)
    2504 {
    2505     Log6Func(("%s\n", fOn ? "on" : "off"));
    2506     if (fOn)
    2507         pThisR3->led.Asserted.s.fReading = pThisR3->led.Actual.s.fReading = 1;
    2508     else
    2509         pThisR3->led.Actual.s.fReading = fOn;
    2510 }
     2346
    25112347/**
    25122348 * @interface_method_impl{PDMIBASE,pfnQueryInterface,
     
    25142350static DECLCALLBACK(void *) virtioNetR3QueryInterface(struct PDMIBASE *pInterface, const char *pszIID)
    25152351{
    2516     PVIRTIONETR3 pThisR3 = RT_FROM_MEMBER(pInterface, VIRTIONETR3, IBase);
    2517 
    2518     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN,   &pThisR3->INetworkDown);
    2519     PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisR3->INetworkConfig);
    2520     PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,          &pThisR3->IBase);
    2521     PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS,      &pThisR3->ILeds);
     2352    PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase);
     2353
     2354    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN,   &pThisCC->INetworkDown);
     2355    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
     2356    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE,          &pThisCC->IBase);
     2357    PDMIBASE_RETURN_INTERFACE(pszIID, PDMILEDPORTS,      &pThisCC->ILeds);
    25222358    return NULL;
    25232359}
     
    25292365{
    25302366    PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
     2367
    25312368    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    25322369    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    2533 
    25342370
    25352371    for (unsigned qIdx = 0; qIdx < pThis->cVirtQueues; qIdx++)
     
    25412377            pWorker->hEvtProcess = NIL_SUPSEMEVENT;
    25422378        }
     2379        if (pThisCC->aWorkers[qIdx].pThread)
     2380        {
     2381            /* Destroy the thread. */
     2382            int rcThread;
     2383            int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[qIdx].pThread, &rcThread);
     2384            if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
     2385                AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
     2386           pThisCC->aWorkers[qIdx].pThread = NULL;
     2387        }
    25432388    }
    25442389
     
    25662411    pThisCC->IBase.pfnQueryInterface = virtioNetR3QueryInterface;
    25672412    pThisCC->ILeds.pfnQueryStatusLed = virtioNetR3QueryStatusLed;
    2568     pThisCC->led.uMagic = PDMLED_MAGIC;
     2413    pThisCC->led.u32Magic = PDMLED_MAGIC;
     2414
     2415    /* Interfaces */
     2416    pThisCC->INetworkDown.pfnWaitReceiveAvail = virtioNetR3NetworkDown_WaitReceiveAvail;
     2417    pThisCC->INetworkDown.pfnReceive          = virtioNetR3NetworkDown_Receive;
     2418    pThisCC->INetworkDown.pfnReceiveGso       = virtioNetR3NetworkDown_ReceiveGso;
     2419    pThisCC->INetworkDown.pfnXmitPending      = virtioNetR3NetworkDown_XmitPending;
     2420    pThisCC->INetworkConfig.pfnGetMac         = virtioNetR3NetworkConfig_GetMac;
     2421    pThisCC->INetworkConfig.pfnGetLinkState   = virtioNetR3NetworkConfig_GetLinkState;
     2422    pThisCC->INetworkConfig.pfnSetLinkState   = virtioNetR3NetworkConfig_SetLinkState;
    25692423
    25702424    /*
     
    25742428
    25752429    /* Get config params */
    2576     int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au, sizeof(pThis->macConfigured));
     2430    int rc = pHlp->pfnCFGMQueryBytes(pCfg, "MAC", pThis->macConfigured.au8, sizeof(pThis->macConfigured));
    25772431    if (RT_FAILURE(rc))
    25782432        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get MAC address"));
     
    25832437
    25842438    uint32_t uStatNo = iInstance;
    2585     rc = pHlp->pfnCFGMQueryuDef(pCfg, "StatNo", &uStatNo, iInstance);
     2439    rc = pHlp->pfnCFGMQueryU32Def(pCfg, "StatNo", &uStatNo, iInstance);
    25862440    if (RT_FAILURE(rc))
    25872441        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"StatNo\" value"));
    25882442
    2589     rc = pHlp->pfnCFGMQueryuDef(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */
     2443    rc = pHlp->pfnCFGMQueryU32Def(pCfg, "LinkUpDelay", &pThis->cMsLinkUpDelay, 5000); /* ms */
    25902444    if (RT_FAILURE(rc))
    25912445        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the value of 'LinkUpDelay'"));
     
    26002454
    26012455    /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */
    2602     memcpy(pThis->virtioNetConfig.uMacAddress, pThis->macConfigured.au, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
     2456    memcpy(pThis->virtioNetConfig.uMacAddress.au8, pThis->macConfigured.au8, sizeof(pThis->virtioNetConfig.uMacAddress)); /* TBD */
    26032457
    26042458    /*
     
    26162470    /* Initialize the generic Virtio core: */
    26172471    pThisCC->Virtio.pfnStatusChanged        = virtioNetR3StatusChanged;
    2618     pThisCC->Virtio.pfnQueueNotified        = virtioNetR3Notified;
     2472    pThisCC->Virtio.pfnQueueNotified        = virtioNetR3QueueNotified;
     2473    pThisCC->Virtio.pfnDevCapRead           = virtioNetR3DevCapRead;
     2474    pThisCC->Virtio.pfnDevCapWrite          = virtioNetR3DevCapWrite;
    26192475
    26202476    VIRTIOPCIPARAMS VirtioPciParams;
     
    26392495    pThis->cVirtqPairs =   pThis->fNegotiatedFeatures & VIRTIONET_F_MQ
    26402496                         ? pThis->virtioNetConfig.uMaxVirtqPairs : 1;
    2641     pThis->cVirtQueues = pThis->cVirtqPairs + 1;
     2497    pThis->cVirtQueues += pThis->cVirtqPairs * 2;
     2498
     2499    /* Create Link Up Timer */
     2500    rc = PDMDevHlpTimerCreate(pDevIns, TMCLOCK_VIRTUAL, virtioNetR3LinkUpTimer, NULL, TMTIMER_FLAGS_NO_CRIT_SECT,
     2501                              "VirtioNet Link Up Timer", &pThisCC->hLinkUpTimer);
    26422502
    26432503    /*
     
    26472507
    26482508    /* Attach the queues and create worker threads for them: */
    2649     for (uint16_t qIdx = 0; qIdx < pThis->cVirtQueues; qIdx++)
    2650     {
     2509    for (uint16_t qIdx = 0; qIdx < pThis->cVirtQueues + 1; qIdx++)
     2510    {
     2511
    26512512        rc = virtioCoreR3QueueAttach(&pThis->Virtio, qIdx, VIRTQNAME(qIdx));
    26522513        if (RT_FAILURE(rc))
     2514        {
     2515            pThis->afQueueAttached[qIdx] = true;
    26532516            continue;
     2517        }
     2518
     2519        /* Skip creating threads for receive queues, only create for transmit queues & control queue */
     2520        if (IS_RX_QUEUE(qIdx))
     2521            continue;
     2522
    26542523        rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->aWorkers[qIdx].pThread,
    26552524                                   (void *)(uintptr_t)qIdx, virtioNetR3WorkerThread,
    2656                                    virtioNetR3WorkerWakeUp, 0, RTTHREADTYPE_IO, VIRTQNAME(qIdx));
     2525                                   virtioNetR3WakeupWorker, 0, RTTHREADTYPE_IO, VIRTQNAME(qIdx));
    26572526        if (rc != VINF_SUCCESS)
    26582527        {
     
    27082577
    27092578#endif /* !IN_RING3 */
     2579
    27102580
    27112581
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r82681 r82863  
    10301030    {
    10311031        PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg];
    1032         uint64_t dstSgStart = (uint64_t)paSeg->pGcSeg;
     1032        uint64_t dstSgStart = (uint64_t)paSeg->gcPhys;
    10331033        uint64_t dstSgLen   = (uint64_t)paSeg->cbSeg;
    1034         uint64_t dstSgCur   = (uint64_t)pSgPhysReturn->pGcSegCur;
     1034        uint64_t dstSgCur   = (uint64_t)pSgPhysReturn->gcPhysCur;
    10351035        cbCopied = RT_MIN((uint64_t)pSgBuf->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
    1036         PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->pGcSegCur, pSgBuf->pvSegCur, cbCopied);
     1036        PDMDevHlpPCIPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->gcPhysCur, pSgBuf->pvSegCur, cbCopied);
    10371037        RTSgBufAdvance(pSgBuf, cbCopied);
    10381038        virtioCoreSgBufAdvance(pSgPhysReturn, cbCopied);
     
    10711071    {
    10721072        PVIRTIOSGSEG paSeg  = &pSgPhysSend->paSegs[pSgPhysSend->idxSeg];
    1073         uint64_t srcSgStart = (uint64_t)paSeg->pGcSeg;
     1073        uint64_t srcSgStart = (uint64_t)paSeg->gcPhys;
    10741074        uint64_t srcSgLen   = (uint64_t)paSeg->cbSeg;
    1075         uint64_t srcSgCur   = (uint64_t)pSgPhysSend->pGcSegCur;
     1075        uint64_t srcSgCur   = (uint64_t)pSgPhysSend->gcPhysCur;
    10761076        cbCopied = RT_MIN((uint64_t)pSgBuf->cbSegLeft, srcSgLen - (srcSgCur - srcSgStart));
    10771077        PDMDevHlpPCIPhysRead(pDevIns,
    1078                           (RTGCPHYS)pSgPhysSend->pGcSegCur, pSgBuf->pvSegCur, cbCopied);
     1078                          (RTGCPHYS)pSgPhysSend->gcPhysCur, pSgBuf->pvSegCur, cbCopied);
    10791079        RTSgBufAdvance(pSgBuf, cbCopied);
    10801080        virtioCoreSgBufAdvance(pSgPhysSend, cbCopied);
     
    24132413            PDMDevHlpSUPSemEventClose(pDevIns, pWorker->hEvtProcess);
    24142414            pWorker->hEvtProcess = NIL_SUPSEMEVENT;
     2415        }
     2416
     2417        if (pThisCC->aWorkers[qIdx].pThread)
     2418        {
     2419            /* Destroy the thread. */
     2420            int rcThread;
     2421            int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[qIdx].pThread, &rcThread);
     2422            if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
     2423                AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n",
     2424                                 __FUNCTION__, rc, rcThread));
     2425           pThisCC->aWorkers[qIdx].pThread = NULL;
    24152426        }
    24162427    }
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r82681 r82863  
    256256}
    257257
    258 #if 0 /* unused - This may eventually be used to set no-notify for the ring as an optimization */
    259258DECLINLINE(void) virtioWriteUsedFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint32_t fFlags)
    260259{
     
    265264                          &fFlags, sizeof(fFlags));
    266265}
    267 #endif
    268266
    269267#if 0 /* unused - *May* be used when VIRTIO_F_EVENT_IDX optional feature is implemented VirtIO 1.0, 2.4.9.2*/
     
    278276#endif
    279277
     278
    280279/** @} */
    281280
     
    291290    if (cSegs && paSegs)
    292291    {
    293         pGcSgBuf->pGcSegCur = paSegs[0].pGcSeg;
     292        pGcSgBuf->gcPhysCur = paSegs[0].gcPhys;
    294293        pGcSgBuf->cbSegLeft = paSegs[0].cbSeg;
    295294    }
    296295    else
    297296    {
    298         pGcSgBuf->pGcSegCur = 0;
     297        pGcSgBuf->gcPhysCur = 0;
    299298        pGcSgBuf->cbSegLeft = 0;
    300299    }
     
    316315
    317316    AssertMsg(    pGcSgBuf->cbSegLeft <= 128 * _1M
    318               && (RTGCPHYS)pGcSgBuf->pGcSegCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg
    319               && (RTGCPHYS)pGcSgBuf->pGcSegCur + pGcSgBuf->cbSegLeft <=
    320                    (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,
    321                  ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->pGcSegCur=%p pGcSgBuf->cbSegLeft=%zd "
    322                   "pGcSgBuf->paSegs[%d].pGcSeg=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",
    323                   pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->pGcSegCur, pGcSgBuf->cbSegLeft,
    324                   pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg, pGcSgBuf->idxSeg,
     317              && (RTGCPHYS)pGcSgBuf->gcPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys
     318              && (RTGCPHYS)pGcSgBuf->gcPhysCur + pGcSgBuf->cbSegLeft <=
     319                   (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,
     320                 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->gcPhysCur=%p pGcSgBuf->cbSegLeft=%zd "
     321                  "pGcSgBuf->paSegs[%d].gcPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",
     322                  pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->gcPhysCur, pGcSgBuf->cbSegLeft,
     323                  pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys, pGcSgBuf->idxSeg,
    325324                  pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg));
    326325
    327326    cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft);
    328     pGcBuf = pGcSgBuf->pGcSegCur;
     327    pGcBuf = pGcSgBuf->gcPhysCur;
    329328    pGcSgBuf->cbSegLeft -= cbData;
    330329    if (!pGcSgBuf->cbSegLeft)
     
    334333        if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs)
    335334        {
    336             pGcSgBuf->pGcSegCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].pGcSeg;
     335            pGcSgBuf->gcPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys;
    337336            pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg;
    338337        }
     
    340339    }
    341340    else
    342         pGcSgBuf->pGcSegCur = pGcSgBuf->pGcSegCur + cbData;
     341        pGcSgBuf->gcPhysCur = pGcSgBuf->gcPhysCur + cbData;
    343342
    344343    return pGcBuf;
     
    352351    if (pGcSgBuf->cSegs)
    353352    {
    354         pGcSgBuf->pGcSegCur = pGcSgBuf->paSegs[0].pGcSeg;
     353        pGcSgBuf->gcPhysCur = pGcSgBuf->paSegs[0].gcPhys;
    355354        pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg;
    356355    }
    357356    else
    358357    {
    359         pGcSgBuf->pGcSegCur = 0;
     358        pGcSgBuf->gcPhysCur = 0;
    360359        pGcSgBuf->cbSegLeft = 0;
    361360    }
     
    541540#endif /* IN_RING3 */
    542541
    543 /**
    544  * See API comments in header file for description
    545  */
    546 int virtioQueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue)
    547 {
    548     Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
    549     PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
    550 
    551     AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],
    552                     ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
    553 
    554     if (virtioCoreQueueIsEmpty(pVirtio->pDevIns, pVirtio, idxQueue))
    555         return VERR_NOT_AVAILABLE;
    556 
    557     Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));
    558     pVirtq->uAvailIdx++;
    559 
    560     return VINF_SUCCESS;
    561 }
    562542
    563543/**
     
    648628        }
    649629
    650         pSeg->pGcSeg = desc.GCPhysBuf;
     630        pSeg->gcPhys = desc.GCPhysBuf;
    651631        pSeg->cbSeg = desc.cb;
    652632
     
    679659}
    680660
     661/*
     662 * Notifies guest (via ISR or MSI-X) of device configuration change
     663 *
     664 * @param   pVirtio     Pointer to the shared virtio state.
     665 */
     666void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio)
     667{
     668    virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false);
     669
     670}
     671
     672/**
     673 * Enable or Disable notification for the specified queue
     674 *
     675 * @param   pVirtio     Pointer to the shared virtio state.
     676 * @param   idxQueue    Queue number
     677 * @param   fEnabled    Selects notification mode (enabled or disabled)
     678 */
     679void virtioCoreQueueSetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled)
     680{
     681    uint16_t fFlags = virtioReadUsedFlags(pVirtio->pDevIns, pVirtio, idxQueue);
     682
     683    if (fEnabled)
     684        fFlags &= ~ VIRTQ_USED_F_NO_NOTIFY;
     685    else
     686        fFlags |= VIRTQ_USED_F_NO_NOTIFY;
     687
     688    virtioWriteUsedFlags(pVirtio->pDevIns, pVirtio, idxQueue, fFlags);
     689}
     690
     691
     692/**
     693 * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
     694 * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
     695 *
     696 * @param   pVirtio     Pointer to the virtio state.
     697 */
     698void virtioCoreResetAll(PVIRTIOCORE pVirtio)
     699{
     700    LogFunc(("\n"));
     701    pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
     702    if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
     703    {
     704        pVirtio->fGenUpdatePending = true;
     705        virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */);
     706    }
     707}
     708/**
     709 * Get count of new (e.g. pending) elements in available ring.
     710 *
     711 * @param   pDevIns     The device instance.
     712 * @param   pVirtio     Pointer to the shared virtio state.
     713 * @param   idxQueue    Queue number
     714 *
     715 * @returns how many entries have been added to ring as a delta of the consumer's
     716 *          avail index and the queue's guest-side current avail index.
     717 */
     718int  virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)
     719{
     720    uint16_t uAvailRingIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue);
     721    uint16_t uNextAvailIdx = pVirtio->virtqState[idxQueue].uAvailIdx;
     722    int16_t  iDelta = uAvailRingIdx - uNextAvailIdx;
     723    uint16_t uDelta = uAvailRingIdx - uNextAvailIdx;
     724    return iDelta >= 0 ? uDelta : VIRTQ_MAX_CNT + uDelta;
     725}
    681726/**
    682727 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
    683  * chain into its OUT (to device) and IN to guest components.
     728 * chain into its OUT (to device) and IN to guest components, but does NOT remove it from
     729 * the 'avail' queue. I.e. doesn't advance the index.  This can be used with virtioQueueSkip(),
     730 * which *does* advance the avail index. Together they facilitate a mechanism that allows
     731 * work with a queue element (descriptor chain) to be aborted if necessary, by not advancing
     732 * the pointer, or, upon success calling the skip function (above) to move to the next element.
    684733 *
    685734 * Additionally it converts the OUT desc chain data to a contiguous virtual
     
    691740 * @param   pVirtio     Pointer to the shared virtio state.
    692741 * @param   idxQueue    Queue number
    693  * @param   fRemove     flags whether to remove desc chain from queue (false = peek)
    694742 * @param   ppDescChain Address to store pointer to descriptor chain that contains the
    695743 *                      pre-processed transaction information pulled from the virtq.
     744 *
     745 * @returns VBox status code:
     746 * @retval  VINF_SUCCESS         Success
     747 * @retval  VERR_INVALID_STATE   VirtIO not in ready state (asserted).
     748 * @retval  VERR_NOT_AVAILABLE   If the queue is empty.
     749 */
     750
     751int virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
     752                         PPVIRTIO_DESC_CHAIN_T ppDescChain)
     753{
     754    return virtioCoreR3QueueGet(pDevIns, pVirtio,  idxQueue, ppDescChain, false);
     755}
     756
     757/**
     758 * Skip the next entry in the specified queue (typically used with virtioCoreR3QueuePeek())
     759 *
     760 * @param   pVirtio     Pointer to the virtio state.
     761 * @param   idxQueue    Index of queue
     762 */
     763int virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue)
     764{
     765    Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));
     766    PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue];
     767
     768    AssertMsgReturn(IS_DRIVER_OK(pVirtio) && pVirtio->uQueueEnable[idxQueue],
     769                    ("Guest driver not in ready state.\n"), VERR_INVALID_STATE);
     770
     771    if (virtioCoreQueueIsEmpty(pVirtio->pDevIns, pVirtio, idxQueue))
     772        return VERR_NOT_AVAILABLE;
     773
     774    Log2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));
     775    pVirtq->uAvailIdx++;
     776
     777    return VINF_SUCCESS;
     778}
     779
     780/**
     781 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor
     782 * chain into its OUT (to device) and IN to guest components.
     783 *
     784 * Additionally it converts the OUT desc chain data to a contiguous virtual
     785 * memory buffer for easy consumption by the caller. The caller must return the
     786 * descriptor chain pointer via virtioCoreR3QueuePut() and then call virtioCoreQueueSync()
     787 * at some point to return the data to the guest and complete the transaction.
     788 *
     789 * @param   pDevIns     The device instance.
     790 * @param   pVirtio     Pointer to the shared virtio state.
     791 * @param   idxQueue    Queue number
     792 * @param   ppDescChain Address to store pointer to descriptor chain that contains the
     793 *                      pre-processed transaction information pulled from the virtq.
     794 * @param   fRemove     flags whether to remove desc chain from queue (false = peek)
    696795 *
    697796 * @returns VBox status code:
     
    734833 * @param   idxQueue        Queue number
    735834 *
    736  * @param   pSgVirtReturn   Points toscatter-gather buffer of virtual memory
     835 * @param   pSgVirtReturn   Points to scatter-gather buffer of virtual memory
    737836 *                          segments the caller is returning to the guest.
    738837 *
     
    768867
    769868    size_t cbCopy = 0;
    770     size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn);
    771     virtioCoreSgBufReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */
    772     while (cbRemain)
    773     {
    774         PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg];
    775         uint64_t dstSgStart = (uint64_t)paSeg->pGcSeg;
    776         uint64_t dstSgLen   = (uint64_t)paSeg->cbSeg;
    777         uint64_t dstSgCur   = (uint64_t)pSgPhysReturn->pGcSegCur;
    778         cbCopy = RT_MIN((uint64_t)pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
    779         PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->pGcSegCur, pSgVirtReturn->pvSegCur, cbCopy);
    780         RTSgBufAdvance(pSgVirtReturn, cbCopy);
    781         virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy);
    782         cbRemain -= cbCopy;
    783     }
    784 
    785     if (fFence)
    786         RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */
     869
     870    if (pSgVirtReturn)
     871    {
     872        size_t cbRemain = RTSgBufCalcTotalLength(pSgVirtReturn);
     873        virtioCoreSgBufReset(pSgPhysReturn); /* Reset ptr because req data may have already been written */
     874        while (cbRemain)
     875        {
     876            PVIRTIOSGSEG paSeg = &pSgPhysReturn->paSegs[pSgPhysReturn->idxSeg];
     877            uint64_t dstSgStart = (uint64_t)paSeg->gcPhys;
     878            uint64_t dstSgLen   = (uint64_t)paSeg->cbSeg;
     879            uint64_t dstSgCur   = (uint64_t)pSgPhysReturn->gcPhysCur;
     880            cbCopy = RT_MIN((uint64_t)pSgVirtReturn->cbSegLeft, dstSgLen - (dstSgCur - dstSgStart));
     881            PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->gcPhysCur, pSgVirtReturn->pvSegCur, cbCopy);
     882            RTSgBufAdvance(pSgVirtReturn, cbCopy);
     883            virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy);
     884            cbRemain -= cbCopy;
     885        }
     886
     887        if (fFence)
     888            RT_UNTRUSTED_NONVOLATILE_COPY_FENCE(); /* needed? */
     889
     890        Assert(!(cbCopy >> 32));
     891    }
     892
    787893
    788894    /* If this write-ahead crosses threshold where the driver wants to get an event flag it */
     
    790896        if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue))
    791897            pVirtq->fEventThresholdReached = true;
    792 
    793     Assert(!(cbCopy >> 32));
    794898
    795899    /*
     
    9591063    else if (uMsixVector != VIRTIO_MSI_NO_VECTOR)
    9601064        PDMDevHlpPCISetIrq(pDevIns, pVirtio->uMsixConfig, PDM_IRQ_LEVEL_LOW);
    961 }
    962 
    963 
    964 
    965 /**
    966  * Initiate orderly reset procedure. This is an exposed API for clients that might need it.
    967  * Invoked by client to reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
    968  */
    969 void virtioCoreResetAll(PVIRTIOCORE pVirtio)
    970 {
    971     LogFunc(("\n"));
    972     pVirtio->uDeviceStatus |= VIRTIO_STATUS_DEVICE_NEEDS_RESET;
    973     if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)
    974     {
    975         pVirtio->fGenUpdatePending = true;
    976         virtioKick(pVirtio->pDevIns, pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */);
    977     }
    9781065}
    9791066
     
    13941481 *
    13951482 * This MMIO handler specifically supports the VIRTIO_PCI_CAP_PCI_CFG capability defined
    1396  * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited to cb == 1, cb == 2, or cb==4 type writes.
     1483 * in the VirtIO 1.0 specification, section 4.1.4.7, and as such is limited
     1484 * to cb == 1, cb == 2, or cb==4 type writes.
    13971485 */
    13981486static DECLCALLBACK(VBOXSTRICTRC) virtioMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h

    r82151 r82863  
    7171typedef struct VIRTIOSGSEG                                      /**< An S/G entry                              */
    7272{
    73     RTGCPHYS pGcSeg;                                            /**< Pointer to the segment buffer             */
     73    RTGCPHYS gcPhys;                                            /**< Pointer to the segment buffer             */
    7474    size_t  cbSeg;                                              /**< Size of the segment buffer                */
    7575} VIRTIOSGSEG;
     
    8484    unsigned  cSegs;                                            /**< Number of segments                        */
    8585    unsigned  idxSeg;                                           /**< Current segment we are in                 */
    86     RTGCPHYS  pGcSegCur;                                        /**< Ptr to byte within the current seg        */
     86    RTGCPHYS  gcPhysCur;                                        /**< Ptr to byte within the current seg        */
    8787    size_t    cbSegLeft;                                        /**< # of bytes left in the current segment    */
    8888} VIRTIOSGBUF;
     
    377377                             uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain);
    378378
     379int  virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
     380                           PPVIRTIO_DESC_CHAIN_T ppDescChain);
     381
     382int  virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue);
     383
    379384int  virtioCoreR3QueueGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue,
    380385                          PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove);
     386
    381387int  virtioCoreR3QueuePut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn,
    382388                          PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence);
     389
     390int  virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue);
    383391int  virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue);
    384392bool virtioCoreQueueIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue);
    385393void virtioCoreQueueEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled);
    386 
    387 /**
    388  * Skip the next entry in the specified queue
    389  *
    390  * @param   pVirtio     Pointer to the virtio state.
    391  * @param   idxQueue    Index of queue
    392  *
    393  */
    394 int virtioQueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue);
    395 
    396 /**
    397  * Reset the device and driver (see VirtIO 1.0 section 2.1.1/2.1.2)
    398  *
    399  * @param   pVirtio     Pointer to the virtio state.
    400  */
     394void virtioCoreQueueSetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled);
     395void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio);
    401396void virtioCoreResetAll(PVIRTIOCORE pVirtio);
    402397
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette