VirtualBox

Changeset 84774 in vbox for trunk/src/VBox/Devices/Network


Ignore:
Timestamp:
Jun 11, 2020 6:01:00 AM (5 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
138574
Message:

Network/DevVirtioNet_1_0.cpp: Fixed controlq hang, reduced use of indexes to refer to queues in DevVirtioNet_1_0.cpp for a cleaner implemention. Streamlined and improved debug logging. Added DbgHelp functions, removed the virtq empty check API and implemented it as a macro based on counting queue entries instead..

File:
1 edited

Legend:

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

    r84468 r84774  
    5959#include "VBoxDD.h"
    6060
    61 /* After debugging single instance case, restore instance name logging */
    62 #define INSTANCE(pState) (char *)(pState->szInstanceName ? pState->szInstanceName : "") // Avoid requiring RT_NOREF in some funcs
    63 
    6461#define VIRTIONET_SAVED_STATE_VERSION          UINT32_C(1)
    6562#define VIRTIONET_MAX_QPAIRS                   1
     
    7067#define VIRTIONET_PREALLOCATE_RX_SEG_COUNT     32
    7168
    72 #define VIRTQNAME(idxQueue)       (pThis->aszVirtqNames[idxQueue])
     69#define VIRTQNAME(idxQueue)       (pThis->aQueues[idxQueue]->szName)
    7370#define CBVIRTQNAME(idxQueue)     RTStrNLen(VIRTQNAME(idxQueue), sizeof(VIRTQNAME(idxQueue)))
    7471#define FEATURE_ENABLED(feature)  RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)
    7572#define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature))
    7673#define FEATURE_OFFERED(feature)  VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature
     74
     75#define IS_VIRTQ_EMPTY(pDevIns, pVirtio, idxQueue) \
     76            (virtioCoreQueueAvailCount(pDevIns, pVirtio, idxQueue) == 0)
    7777
    7878#define SET_LINK_UP(pState) \
     
    301301
    302302/**
     303 * device-specific queue info
     304 */
     305struct VIRTIONETWORKER;
     306struct VIRTIONETWORKERR3;
     307
     308typedef struct VIRTIONETQUEUE
     309{
     310    struct VIRTIONETWORKER         *pWorker;                    /**< Pointer to R0 worker struct                      */
     311    struct VIRTIONETWORKERR3       *pWorkerR3;                  /**< Pointer to R3 worker struct                      */
     312    uint16_t                       idx;                         /**< Index of this queue                              */
     313    uint16_t                       align;
     314    char                           szName[VIRTIO_MAX_QUEUE_NAME_SIZE]; /**< Queue name                                */
     315    bool                           fCtlQueue;                   /**< If set this queue is the control queue           */
     316    bool                           fHasWorker;                  /**< If set this queue has an associated worker       */
     317    bool                           fAttachedToVirtioCore;       /**< Set if queue attached to virtio core             */
     318    uint8_t                        pad;
     319} VIRTIONETQUEUE, *PVIRTIONETQUEUE;
     320
     321/**
    303322 * Worker thread context, shared state.
    304323 */
     
    306325{
    307326    SUPSEMEVENT                     hEvtProcess;                /**< handle of associated sleep/wake-up semaphore      */
     327    PVIRTIONETQUEUE                 pQueue;                     /**< pointer to queue                                  */
     328    uint16_t                        idx;                        /**< Index of this worker                              */
    308329    bool volatile                   fSleeping;                  /**< Flags whether worker thread is sleeping or not    */
    309330    bool volatile                   fNotified;                  /**< Flags whether worker thread notified              */
     331    bool                            fAssigned;                  /**< Flags whether worker thread has been set up       */
     332    uint8_t                         pad;
    310333} VIRTIONETWORKER;
    311 /** Pointer to a VirtIO SCSI worker. */
     334/** Pointer to a virtio net worker. */
    312335typedef VIRTIONETWORKER *PVIRTIONETWORKER;
    313336
     
    318341{
    319342    R3PTRTYPE(PPDMTHREAD)           pThread;                    /**< pointer to worker thread's handle                 */
    320     uint16_t                        idxQueue;                   /**< Index of associated queue                         */
     343    PVIRTIONETQUEUE                 pQueue;                     /**< pointer to queue                                  */
     344    uint16_t                        idx;                        /**< Index of this worker                              */
     345    uint16_t                        pad;
    321346} VIRTIONETWORKERR3;
    322 /** Pointer to a VirtIO SCSI worker. */
     347/** Pointer to a virtio net worker. */
    323348typedef VIRTIONETWORKERR3 *PVIRTIONETWORKERR3;
    324349
     
    340365
    341366    /** Track which VirtIO queues we've attached to */
    342     bool                    afQueueAttached[VIRTIONET_MAX_QUEUES];
    343 
    344     /** Device-specific spec-based VirtIO VIRTQNAMEs */
    345     char                    aszVirtqNames[VIRTIONET_MAX_QUEUES][VIRTIO_MAX_QUEUE_NAME_SIZE];
    346 
    347     /** Instance name */
    348     char                    szInstanceName[16];
    349 
     367    VIRTIONETQUEUE          aQueues[VIRTIONET_MAX_QUEUES];
     368
     369    /** PDM device Instance name */
     370    char                    szInst[16];
     371
     372    /** VirtIO features negotiated with the guest, including generic core and device specific */
     373    uint64_t                fNegotiatedFeatures;
     374
     375    /** Number of Rx/Tx queue pairs (only one if MQ feature not negotiated */
    350376    uint16_t                cVirtqPairs;
    351377
     378    /** Number of virtqueues total (which includes each queue of each pair plus one control queue */
    352379    uint16_t                cVirtQueues;
    353380
     381    /** Number of worker threads (one for the control queue and one for each Tx queue) */
    354382    uint16_t                cWorkers;
    355383
    356     uint64_t                fNegotiatedFeatures;
    357 
    358     SUPSEMEVENT             hTxEvent;
     384    /** Alighnment */
     385    uint16_t                alignment;
    359386
    360387    /** Indicates transmission in progress -- only one thread is allowed. */
    361388    uint32_t                uIsTransmitting;
    362389
     390    /** virtio-net-1-dot-0 (in milliseconds). */
     391    uint32_t                cMsLinkUpDelay;
     392
     393    /** The number of actually used slots in aMacMulticastFilter. */
     394    uint32_t                cMulticastFilterMacs;
     395
     396    /** The number of actually used slots in aMacUniicastFilter. */
     397    uint32_t                cUnicastFilterMacs;
     398
     399    /** Semaphore leaf device's thread waits on until guest driver sends empty Rx bufs */
     400    SUPSEMEVENT             hEventRxDescAvail;
     401
     402    /** Array of MAC multicast addresses accepted by RX filter. */
     403    RTMAC                   aMacMulticastFilter[VIRTIONET_MAC_FILTER_LEN];
     404
     405    /** Array of MAC unicast addresses accepted by RX filter. */
     406    RTMAC                   aMacUnicastFilter[VIRTIONET_MAC_FILTER_LEN];
     407
     408    /** Default MAC address which rx filtering accepts */
     409    RTMAC                   rxFilterMacDefault;
     410
    363411    /** MAC address obtained from the configuration. */
    364412    RTMAC                   macConfigured;
    365413
    366     /** Default MAC address which rx filtering accepts */
    367     RTMAC                   rxFilterMacDefault;
     414    /** Bit array of VLAN filter, one bit per VLAN ID. */
     415    uint8_t                 aVlanFilter[VIRTIONET_MAX_VLAN_ID / sizeof(uint8_t)];
     416
     417    /** Set if PDM leaf device at the network interface is starved for Rx buffers */
     418    bool volatile           fLeafWantsEmptyRxBufs;
     419
     420    /** Number of packet being sent/received to show in debug log. */
     421    uint32_t                uPktNo;
     422
     423    /** Flags whether VirtIO core is in ready state */
     424    uint8_t                 fVirtioReady;
     425
     426    /** Resetting flag */
     427    uint8_t                 fResetting;
     428
     429    /** Quiescing I/O activity flag */
     430    uint8_t                 fQuiescing;
     431
     432    /** Promiscuous mode -- RX filter accepts all packets. */
     433    uint8_t                 fPromiscuous;
     434
     435    /** All multicast mode -- RX filter accepts all multicast packets. */
     436    uint8_t                 fAllMulticast;
     437
     438    /** All unicast mode -- RX filter accepts all unicast packets. */
     439    uint8_t                 fAllUnicast;
     440
     441    /** No multicast mode - Supresses multicast receive */
     442    uint8_t                 fNoMulticast;
     443
     444    /** No unicast mode - Suppresses unicast receive */
     445    uint8_t                 fNoUnicast;
     446
     447    /** No broadcast mode - Supresses broadcast receive */
     448    uint8_t                 fNoBroadcast;
    368449
    369450    /** True if physical cable is attached in configuration. */
    370451    bool                    fCableConnected;
    371 
    372     /** virtio-net-1-dot-0 (in milliseconds). */
    373     uint32_t                cMsLinkUpDelay;
    374 
    375     uint32_t                alignment;
    376 
    377     /** Number of packet being sent/received to show in debug log. */
    378     uint32_t                uPktNo;
    379 
    380     /** N/A: */
    381     bool volatile           fLeafWantsRxBuffers;
    382 
    383     SUPSEMEVENT             hEventRxDescAvail;
    384 
    385     /** Flags whether VirtIO core is in ready state */
    386     uint8_t                 fVirtioReady;
    387 
    388     /** Resetting flag */
    389     uint8_t                 fResetting;
    390 
    391     /** Quiescing I/O activity flag */
    392     uint8_t                 fQuiescing;
    393 
    394     /** Promiscuous mode -- RX filter accepts all packets. */
    395     uint8_t                 fPromiscuous;
    396 
    397     /** All multicast mode -- RX filter accepts all multicast packets. */
    398     uint8_t                 fAllMulticast;
    399 
    400     /** All unicast mode -- RX filter accepts all unicast packets. */
    401     uint8_t                 fAllUnicast;
    402 
    403     /** No multicast mode - Supresses multicast receive */
    404     uint8_t                 fNoMulticast;
    405 
    406     /** No unicast mode - Suppresses unicast receive */
    407     uint8_t                 fNoUnicast;
    408 
    409     /** No broadcast mode - Supresses broadcast receive */
    410     uint8_t                 fNoBroadcast;
    411 
    412     /** The number of actually used slots in aMacMulticastFilter. */
    413     uint32_t                cMulticastFilterMacs;
    414 
    415     /** Array of MAC multicast addresses accepted by RX filter. */
    416     RTMAC                   aMacMulticastFilter[VIRTIONET_MAC_FILTER_LEN];
    417 
    418     /** The number of actually used slots in aMacUniicastFilter. */
    419     uint32_t                cUnicastFilterMacs;
    420 
    421     /** Array of MAC unicast addresses accepted by RX filter. */
    422     RTMAC                   aMacUnicastFilter[VIRTIONET_MAC_FILTER_LEN];
    423 
    424     /** Bit array of VLAN filter, one bit per VLAN ID. */
    425     uint8_t                 aVlanFilter[VIRTIONET_MAX_VLAN_ID / sizeof(uint8_t)];
    426452
    427453    /** @name Statistic
     
    489515    R3PTRTYPE(PPDMINETWORKUP)       pDrv;
    490516
    491     R3PTRTYPE(PPDMTHREAD)           pTxThread;
    492 
    493517    /** Link Up(/Restore) Timer. */
    494518    TMTIMERHANDLE                   hLinkUpTimer;
    495 
    496     /** Queue to send tasks to R3. - HC ptr */
    497     R3PTRTYPE(PPDMQUEUE)            pNotifierQueueR3;
    498519
    499520    /** True if in the process of quiescing I/O */
     
    541562typedef CTX_SUFF(PVIRTIONET) PVIRTIONETCC;
    542563
     564#ifdef IN_RING3
     565static DECLCALLBACK(int) virtioNetR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread);
     566
     567DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread)
     568{
     569    if (!pThread)
     570        return "<null>";
     571
     572    switch(pThread->enmState)
     573    {
     574        case PDMTHREADSTATE_INVALID:
     575            return "invalid state";
     576        case PDMTHREADSTATE_INITIALIZING:
     577            return "initializing";
     578        case PDMTHREADSTATE_SUSPENDING:
     579            return "suspending";
     580        case PDMTHREADSTATE_SUSPENDED:
     581            return "suspended";
     582        case PDMTHREADSTATE_RESUMING:
     583            return "resuming";
     584        case PDMTHREADSTATE_RUNNING:
     585            return "running";
     586        case PDMTHREADSTATE_TERMINATING:
     587            return "terminating";
     588        case PDMTHREADSTATE_TERMINATED:
     589            return "terminated";
     590        default:
     591            return "unknown state";
     592    }
     593}
     594#endif
     595
    543596/**
    544597 * Wakeup the RX thread.
     
    551604
    552605    STAM_COUNTER_INC(&pThis->StatRxOverflowWakeup);
    553 
    554     Log10Func(("%s Waking downstream driver's Rx buf waiter thread\n", INSTANCE(pThis)));
    555     int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail);
    556     AssertRC(rc);
     606    if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
     607    {
     608        Log10Func(("%s Waking downstream device's Rx buf waiter thread\n", pThis->szInst));
     609        int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->hEventRxDescAvail);
     610        AssertRC(rc);
     611    }
    557612}
    558613
     
    565620    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    566621
    567     uint16_t idxWorker;
    568     if (idxQueue == CTRLQIDX)
    569         idxWorker = pThis->cWorkers - 1;
    570     else
    571         idxWorker = idxQueue / 2;
    572 
    573     PVIRTIONETWORKER pWorker = &pThis->aWorkers[idxWorker];
    574     AssertReturnVoid(idxQueue < pThis->cVirtQueues);
     622    PVIRTIONETQUEUE  pQueue = &pThis->aQueues[idxQueue];
     623    PVIRTIONETWORKER pWorker = pQueue->pWorker;
    575624
    576625#if defined (IN_RING3) && defined (LOG_ENABLED)
     
    578627#endif
    579628
    580     Log10Func(("%s %s has available buffers\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    581 
    582629    if (IS_RX_QUEUE(idxQueue))
    583630    {
    584         Log10Func(("%s Receive buffers have been added, waking Rx thread.\n",
    585             INSTANCE(pThis)));
    586         virtioNetWakeupRxBufWaiter(pDevIns);
    587     }
    588     else
     631        uint16_t cBufsAvailable = virtioCoreQueueAvailCount(pDevIns, pVirtio, idxQueue);
     632
     633        if (cBufsAvailable)
     634        {
     635            Log10Func(("%s %u empty bufs added to %s by guest (notifying leaf device)\n",
     636                        pThis->szInst, cBufsAvailable, pQueue->szName));
     637            virtioNetWakeupRxBufWaiter(pDevIns);
     638        }
     639        else
     640            LogRel(("%s \n\n***WARNING: %s notified but no empty bufs added by guest! (skip notifying of leaf device)\n\n",
     641                    pThis->szInst, pQueue->szName));
     642    }
     643    else if (IS_TX_QUEUE(idxQueue) || IS_CTRL_QUEUE(idxQueue))
    589644    {
    590645        /* Wake queue's worker thread up if sleeping (e.g. a Tx queue, or the control queue */
     
    593648            if (ASMAtomicReadBool(&pWorker->fSleeping))
    594649            {
    595                 Log10Func(("%s waking %s worker.\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
     650                Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pQueue->szName));
    596651                int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    597652                AssertRC(rc);
    598653            }
     654            else
     655            {
     656                Log10Func(("%s %s has available buffers - worker already awake\n", pThis->szInst, pQueue->szName));
     657            }
    599658        }
    600     }
     659        else
     660        {
     661            Log10Func(("%s %s has available buffers - waking worker.\n", pThis->szInst, pQueue->szName));
     662        }
     663    }
     664    else
     665        LogRelFunc(("%s unrecognized queue %s (idx=%d) notified\n", pQueue->szName, idxQueue));
    601666}
    602667
     
    608673static DECLCALLBACK(int) virtioNetR3WakeupWorker(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    609674{
    610     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    611     Log10Func(("%s\n", INSTANCE(pThis)));
    612     return PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[(uintptr_t)pThread->pvUser].hEvtProcess);
     675    PVIRTIONET       pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     676    PVIRTIONETWORKER pWorker = (PVIRTIONETWORKER)pThread->pvUser;
     677
     678    Log10Func(("%s\n", pThis->szInst));
     679
     680    return PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    613681}
    614682
     
    616684DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis)
    617685{
     686    RTStrCopy(pThis->aQueues[CTRLQIDX].szName, VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
    618687    for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++)
    619688    {
    620         RTStrPrintf(pThis->aszVirtqNames[RXQIDX(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>",  qPairIdx);
    621         RTStrPrintf(pThis->aszVirtqNames[TXQIDX(qPairIdx)], VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx);
    622     }
    623     RTStrCopy(pThis->aszVirtqNames[CTRLQIDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq");
     689        RTStrPrintf(pThis->aQueues[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_QUEUE_NAME_SIZE, "receiveq<%d>",  qPairIdx);
     690        RTStrPrintf(pThis->aQueues[TXQIDX(qPairIdx)].szName, VIRTIO_MAX_QUEUE_NAME_SIZE, "transmitq<%d>", qPairIdx);
     691    }
    624692}
    625693
     
    637705        return;
    638706
    639     vboxEthPacketDump(INSTANCE(pThis), pszText, pbPacket, (uint32_t)cb);
    640 }
    641 
    642 #ifdef LOG_ENABLED
    643 
    644 void virtioNetDumpGcPhysRxBuf(PPDMDEVINS pDevIns, PVIRTIONET_PKT_HDR_T pRxPktHdr,
    645                      uint16_t cDescs, uint8_t *pvBuf, uint16_t cb, RTGCPHYS gcPhysRxBuf, uint8_t cbRxBuf)
    646 {
    647     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    648     pRxPktHdr->uNumBuffers = cDescs;
    649     if (pRxPktHdr)
    650     {
    651         LogFunc(("-------------------------------------------------------------------\n"));
    652         LogFunc(("rxPktHdr\n"
    653                  "    uFlags ......... %2.2x\n"
    654                  "    uGsoType ....... %2.2x\n"
    655                  "    uHdrLen ........ %4.4x\n"
    656                  "    uGsoSize ....... %4.4x\n"
    657                  "    uChksumStart ... %4.4x\n"
    658                  "    uChksumOffset .. %4.4x\n"
    659                  "    uNumBuffers .... %4.4x\n",
    660                         pRxPktHdr->uFlags,
    661                         pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
    662                         pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
    663 
    664         virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONET_PKT_HDR_T), 0, "Dump of virtual rPktHdr");
    665     }
    666     virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
    667     LogFunc((". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"));
    668     virtioCoreGcPhysHexDump(pDevIns, gcPhysRxBuf, cbRxBuf, 0, "Phys Mem Dump of Rx pkt");
    669     LogFunc(("-------------------------------------------------------------------\n"));
    670 }
    671 
    672 DECLINLINE(void) virtioNetPrintFeatures(VIRTIONET *pThis)
     707    vboxEthPacketDump(pThis->szInst, pszText, pbPacket, (uint32_t)cb);
     708}
     709
     710DECLINLINE(void) virtioNetPrintFeatures(VIRTIONET *pThis, PCDBGFINFOHLP pHlp)
    673711{
    674712    static struct
     
    714752                          isOffered ? "+" : "-", isNegotiated ? "x" : " ", s_aFeatures[i].pcszDesc);
    715753    }
    716     Log3(("VirtIO Net Features Configuration\n\n"
    717           "    Offered  Accepted  Feature              Description\n"
    718           "    -------  --------  -------              -----------\n"
    719           "%s\n", pszBuf));
     754    if (pHlp)
     755        pHlp->pfnPrintf(pHlp, "VirtIO Net Features Configuration\n\n"
     756              "    Offered  Accepted  Feature              Description\n"
     757              "    -------  --------  -------              -----------\n"
     758              "%s\n", pszBuf);
     759#ifdef LOG_ENABLED
     760    else
     761        Log3(("VirtIO Net Features Configuration\n\n"
     762              "    Offered  Accepted  Feature              Description\n"
     763              "    -------  --------  -------              -----------\n"
     764              "%s\n", pszBuf));
     765#endif
    720766    RTMemFree(pszBuf);
    721767}
     768
     769#ifdef LOG_ENABLED
     770void virtioNetDumpGcPhysRxBuf(PPDMDEVINS pDevIns, PVIRTIONET_PKT_HDR_T pRxPktHdr,
     771                     uint16_t cDescs, uint8_t *pvBuf, uint16_t cb, RTGCPHYS GCPhysRxBuf, uint8_t cbRxBuf)
     772{
     773    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     774    pRxPktHdr->uNumBuffers = cDescs;
     775    if (pRxPktHdr)
     776    {
     777        LogFunc(("-------------------------------------------------------------------\n"));
     778        LogFunc(("rxPktHdr\n"
     779                 "    uFlags ......... %2.2x\n"
     780                 "    uGsoType ....... %2.2x\n"
     781                 "    uHdrLen ........ %4.4x\n"
     782                 "    uGsoSize ....... %4.4x\n"
     783                 "    uChksumStart ... %4.4x\n"
     784                 "    uChksumOffset .. %4.4x\n"
     785                 "    uNumBuffers .... %4.4x\n",
     786                        pRxPktHdr->uFlags,
     787                        pRxPktHdr->uGsoType, pRxPktHdr->uHdrLen, pRxPktHdr->uGsoSize,
     788                        pRxPktHdr->uChksumStart, pRxPktHdr->uChksumOffset, pRxPktHdr->uNumBuffers));
     789
     790        virtioCoreHexDump((uint8_t *)pRxPktHdr, sizeof(VIRTIONET_PKT_HDR_T), 0, "Dump of virtual rPktHdr");
     791    }
     792    virtioNetR3PacketDump(pThis, (const uint8_t *)pvBuf, cb, "<-- Incoming");
     793    LogFunc((". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .\n"));
     794
     795    virtioCoreGCPhysHexDump(pDevIns, GCPhysRxBuf, cbRxBuf, 0, "Phys Mem Dump of Rx pkt");
     796    LogFunc(("-------------------------------------------------------------------\n"));
     797}
     798
    722799#endif /* LOG_ENABLED */
     800
     801/**
     802 * @callback_method_impl{FNDBGFHANDLERDEV, virtio-net debugger info callback.}
     803 */
     804static DECLCALLBACK(void) virtioNetR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
     805{
     806    PVIRTIONET     pThis   = PDMDEVINS_2_DATA(pDevIns,  PVIRTIONET);
     807    PVIRTIONETCC   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     808
     809    bool fNone     = pszArgs && *pszArgs == '\0';
     810    bool fAll      = pszArgs && (*pszArgs == 'a' || *pszArgs == 'A'); /* "all"      */
     811    bool fNetwork  = pszArgs && (*pszArgs == 'n' || *pszArgs == 'N'); /* "network"  */
     812    bool fFeatures = pszArgs && (*pszArgs == 'f' || *pszArgs == 'F'); /* "features" */
     813    bool fState    = pszArgs && (*pszArgs == 's' || *pszArgs == 'S'); /* "state"    */
     814    bool fPointers = pszArgs && (*pszArgs == 'p' || *pszArgs == 'P'); /* "pointers" */
     815    bool fQueues   = pszArgs && (*pszArgs == 'q' || *pszArgs == 'Q'); /* "queues    */
     816
     817    /* Show basic information. */
     818    pHlp->pfnPrintf(pHlp,
     819        "\n"
     820        "---------------------------------------------------------------------------\n"
     821        "Debug Info: %s\n"
     822        "        (options: [a]ll, [n]et, [f]eatures, [s]tate, [p]ointers, [q]ueues)\n"
     823        "---------------------------------------------------------------------------\n\n",
     824        pThis->szInst, pDevIns->pReg->szName);
     825
     826    if (fNone)
     827        return;
     828
     829    /* Show offered/unoffered, accepted/rejected features */
     830    if (fAll || fFeatures)
     831    {
     832        virtioCorePrintFeatures(&pThis->Virtio, pHlp);
     833        virtioNetPrintFeatures(pThis, pHlp);
     834        pHlp->pfnPrintf(pHlp, "\n");
     835    }
     836
     837    /* Show queues (and associate worker info if applicable) */
     838    if (fAll || fQueues)
     839    {
     840        pHlp->pfnPrintf(pHlp, "Queue information:\n\n");
     841
     842        for (int idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
     843        {
     844            PVIRTIONETQUEUE pQueue = &pThis->aQueues[idxQueue];
     845
     846            if (pQueue->fHasWorker)
     847            {
     848                PVIRTIONETWORKER pWorker = pQueue->pWorker;
     849                PVIRTIONETWORKERR3 pWorkerR3 = pQueue->pWorkerR3;
     850
     851                if (pWorker->fAssigned)
     852                {
     853                    pHlp->pfnPrintf(pHlp, "    %-15s (pThread: %p %s) ",
     854                        pQueue->szName,
     855                        pWorkerR3->pThread,
     856                        virtioNetThreadStateName(pWorkerR3->pThread));
     857                    if (pQueue->fAttachedToVirtioCore)
     858                    {
     859                        pHlp->pfnPrintf(pHlp, "worker: ");
     860                        pHlp->pfnPrintf(pHlp, "%s", pWorker->fSleeping ? "blocking" : "unblocked");
     861                        pHlp->pfnPrintf(pHlp, "%s", pWorker->fNotified ? ", notified" : "");
     862                    }
     863                    else
     864                    if (pWorker->fNotified)
     865                        pHlp->pfnPrintf(pHlp, "not attached to virtio core");
     866                }
     867            }
     868            else
     869            {
     870                pHlp->pfnPrintf(pHlp, "    %-15s (INetworkDown's thread) %s", pQueue->szName,
     871                    pQueue->fAttachedToVirtioCore  ? "" : "not attached to virtio core");
     872            }
     873            pHlp->pfnPrintf(pHlp, "\n");
     874            virtioCoreR3QueueInfo(pDevIns, pHlp, pszArgs, idxQueue);
     875            pHlp->pfnPrintf(pHlp, "    ---------------------------------------------------------------------\n");
     876            pHlp->pfnPrintf(pHlp, "\n");
     877        }
     878        pHlp->pfnPrintf(pHlp, "\n");
     879    }
     880
     881    /* Show various pointers */
     882    if (fAll || fPointers)
     883    {
     884
     885        pHlp->pfnPrintf(pHlp, "Internal pointers:\n\n");
     886
     887        pHlp->pfnPrintf(pHlp, "    pDevIns ................... %p\n",  pDevIns);
     888        pHlp->pfnPrintf(pHlp, "    PVIRTIONET ................ %p\n",  pThis);
     889        pHlp->pfnPrintf(pHlp, "    PVIRTIONETCC .............. %p\n", pThisCC);
     890        pHlp->pfnPrintf(pHlp, "    pDrvBase .................. %p\n",  pThisCC->pDrvBase);
     891        pHlp->pfnPrintf(pHlp, "    pDrv ...................... %p\n",  pThisCC->pDrv);
     892        pHlp->pfnPrintf(pHlp, "    pDrv ...................... %p\n",  pThisCC->pDrv);
     893        pHlp->pfnPrintf(pHlp, "\n");
     894        pHlp->pfnPrintf(pHlp, "Misc state\n");
     895        pHlp->pfnPrintf(pHlp, "\n");
     896        pHlp->pfnPrintf(pHlp, "    fVirtioReady .............. %d\n",  pThis->fVirtioReady);
     897        pHlp->pfnPrintf(pHlp, "    fGenUpdatePending ......... %d\n",  pThis->Virtio.fGenUpdatePending);
     898        pHlp->pfnPrintf(pHlp, "    fMsiSupport ............... %d\n",  pThis->Virtio.fMsiSupport);
     899        pHlp->pfnPrintf(pHlp, "    uConfigGeneration ......... %d\n",  pThis->Virtio.uConfigGeneration);
     900        pHlp->pfnPrintf(pHlp, "    uDeviceStatus ............. 0x%x\n", pThis->Virtio.uDeviceStatus);
     901        pHlp->pfnPrintf(pHlp, "    cVirtqPairs .,............. %d\n",  pThis->cVirtqPairs);
     902        pHlp->pfnPrintf(pHlp, "    cVirtQueues .,............. %d\n",  pThis->cVirtQueues);
     903        pHlp->pfnPrintf(pHlp, "    cWorkers .................. %d\n",  pThis->cWorkers);
     904        pHlp->pfnPrintf(pHlp, "    MMIO mapping name ......... %d\n",  pThisCC->Virtio.pcszMmioName);
     905
     906    }
     907
     908    /* Show device state info */
     909    if (fAll || fState)
     910    {
     911        pHlp->pfnPrintf(pHlp, "Device state:\n\n");
     912        uint32_t fTransmitting = ASMAtomicReadU32(&pThis->uIsTransmitting);
     913
     914        pHlp->pfnPrintf(pHlp, "    Transmitting: ............. %s\n", fTransmitting ? "true" : "false");
     915        pHlp->pfnPrintf(pHlp, "    Quiescing: ................ %s %s\n",
     916                pThis->fQuiescing ? "true" : "false",
     917                pThis->fQuiescing ? "(" : "",
     918                pThis->fQuiescing ? virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor) : "",
     919                pThis->fQuiescing ? ")" : "");
     920        pHlp->pfnPrintf(pHlp, "    Resetting: ................ %s\n", pThis->fResetting ? "true" : "false");
     921        pHlp->pfnPrintf(pHlp, "\n");
     922    }
     923
     924    /* Show network related information */
     925    if (fAll || fNetwork)
     926    {
     927        pHlp->pfnPrintf(pHlp, "Network configuration:\n\n");
     928
     929        pHlp->pfnPrintf(pHlp, "    MAC: ...................... %RTmac\n", &pThis->macConfigured);
     930        pHlp->pfnPrintf(pHlp, "\n");
     931        pHlp->pfnPrintf(pHlp, "    Cable: .................... %s\n",      pThis->fCableConnected ? "connected" : "disconnected");
     932        pHlp->pfnPrintf(pHlp, "    Link-up delay: ............ %d ms\n",   pThis->cMsLinkUpDelay);
     933        pHlp->pfnPrintf(pHlp, "\n");
     934        pHlp->pfnPrintf(pHlp, "    Accept all multicast: ..... %s\n",      pThis->fAllMulticast  ? "true" : "false");
     935        pHlp->pfnPrintf(pHlp, "    Suppress broadcast: ....... %s\n",      pThis->fNoBroadcast   ? "true" : "false");
     936        pHlp->pfnPrintf(pHlp, "    Suppress unicast: ......... %s\n",      pThis->fNoUnicast     ? "true" : "false");
     937        pHlp->pfnPrintf(pHlp, "    Suppress multicast: ....... %s\n",      pThis->fNoMulticast   ? "true" : "false");
     938        pHlp->pfnPrintf(pHlp, "    Promiscuous: .............. %s\n",      pThis->fPromiscuous   ? "true" : "false");
     939        pHlp->pfnPrintf(pHlp, "\n");
     940        pHlp->pfnPrintf(pHlp, "    Default Rx MAC filter: .... %RTmac\n", pThis->rxFilterMacDefault);
     941        pHlp->pfnPrintf(pHlp, "\n");
     942
     943        pHlp->pfnPrintf(pHlp, "    Unicast filter MACs:\n");
     944
     945        if (!pThis->cUnicastFilterMacs)
     946            pHlp->pfnPrintf(pHlp, "        <none>\n");
     947
     948        for (uint32_t i = 0; i < pThis->cUnicastFilterMacs; i++)
     949            pHlp->pfnPrintf(pHlp, "        %RTmac\n", &pThis->aMacUnicastFilter[i]);
     950
     951        pHlp->pfnPrintf(pHlp, "\n    Multicast filter MACs:\n");
     952
     953        if (!pThis->cMulticastFilterMacs)
     954            pHlp->pfnPrintf(pHlp, "        <none>\n");
     955
     956        for (uint32_t i = 0; i < pThis->cMulticastFilterMacs; i++)
     957            pHlp->pfnPrintf(pHlp, "        %RTmac\n", &pThis->aMacMulticastFilter[i]);
     958
     959        pHlp->pfnPrintf(pHlp, "\n\n");
     960        pHlp->pfnPrintf(pHlp, "    Leaf starved: ............. %s\n",      pThis->fLeafWantsEmptyRxBufs ? "true" : "false");
     961        pHlp->pfnPrintf(pHlp, "\n");
     962
     963    }
     964    pHlp->pfnPrintf(pHlp, "\n");
     965    virtioCoreR3Info(pDevIns, pHlp, pszArgs);
     966    pHlp->pfnPrintf(pHlp, "\n");
     967}
     968
    723969/*
    724970 * Checks whether negotiated features have required flag combinations.
     
    8021048        uint32_t offIntra = offConfig - RT_UOFFSETOF(VIRTIONET_CONFIG_T, member); \
    8031049        if (fWrite) \
    804             LogFunc(("%s Guest attempted to write readonly virtio_pci_common_cfg.%s\n", INSTANCE(pThis), #member)); \
     1050            LogFunc(("%s Guest attempted to write readonly virtio_pci_common_cfg.%s\n", pThis->szInst, #member)); \
    8051051        else \
    8061052        { \
     
    8291075    else
    8301076    {
    831         LogFunc(("%s Bad access by guest to virtio_net_config: off=%u (%#x), cb=%u\n", INSTANCE(pThis), offConfig, offConfig, cb));
     1077        LogFunc(("%s Bad access by guest to virtio_net_config: off=%u (%#x), cb=%u\n", pThis->szInst, offConfig, offConfig, cb));
    8321078        return fWrite ? VINF_SUCCESS : VINF_IOM_MMIO_UNUSED_00;
    8331079    }
     
    8471093    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    8481094
    849     LogFunc(("%s uOffset: %d, cb: %d\n",  INSTANCE(pThis), uOffset, cb));
     1095    LogFunc(("%s uOffset: %d, cb: %d\n",  pThis->szInst, uOffset, cb));
    8501096    RT_NOREF(pThis);
    8511097    return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/);
     
    8591105    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    8601106
    861     Log10Func(("%s uOffset: %d, cb: %d: %.*Rhxs\n", INSTANCE(pThis), uOffset, cb, RT_MAX(cb, 8) , pv));
     1107    Log10Func(("%s uOffset: %d, cb: %d: %.*Rhxs\n", pThis->szInst, uOffset, cb, RT_MAX(cb, 8) , pv));
    8621108    RT_NOREF(pThis);
    8631109    return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, (void *)pv, cb, true /*fWrite*/);
    864 }
    865 
    866 
    867 /*********************************************************************************************************************************
    868 *   Misc                                                                                                                         *
    869 *********************************************************************************************************************************/
    870 
    871 /**
    872  * @callback_method_impl{FNDBGFHANDLERDEV, virtio-net debugger info callback.}
    873  */
    874 static DECLCALLBACK(void) virtioNetR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)
    875 {
    876     PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    877 
    878     /* Parse arguments. */
    879     RT_NOREF2(pThis, pszArgs); //bool fVerbose = pszArgs && strstr(pszArgs, "verbose") != NULL;
    880 
    881     /* Show basic information. */
    882     pHlp->pfnPrintf(pHlp, "%s#%d: virtio-scsci ",
    883                     pDevIns->pReg->szName,
    884                     pDevIns->iInstance);
    8851110}
    8861111
     
    9001125
    9011126    RT_NOREF(pThisCC);
    902     Log7Func(("%s LOAD EXEC!!\n", INSTANCE(pThis)));
     1127    Log7Func(("%s LOAD EXEC!!\n", pThis->szInst));
    9031128
    9041129    AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS);
     
    9141139
    9151140    for (int idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
    916         pHlp->pfnSSMGetBool(pSSM, &pThis->afQueueAttached[idxQueue]);
     1141        pHlp->pfnSSMGetBool(pSSM, &pThis->aQueues[idxQueue].fAttachedToVirtioCore);
    9171142
    9181143    int rc;
     
    9301155        && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns)))
    9311156        LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n",
    932             INSTANCE(pThis), &pThis->macConfigured, &macConfigured));
     1157            pThis->szInst, &pThis->macConfigured, &macConfigured));
    9331158#endif
    9341159
     
    9731198    for (int idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++)
    9741199    {
    975         uint16_t idxQueue = pThisCC->aWorkers[idxWorker].idxQueue;
    976         if (pThis->afQueueAttached[idxQueue])
     1200        PVIRTIONETWORKER pWorker = &pThis->aWorkers[idxWorker];
     1201        PVIRTIONETQUEUE  pQueue  = pWorker->pQueue;
     1202        if (pQueue->fAttachedToVirtioCore)
    9771203        {
    978             Log7Func(("%s Waking %s worker.\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    979             rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[idxWorker].hEvtProcess);
     1204            Log7Func(("%s Waking %s worker.\n", pThis->szInst, pQueue->szName));
     1205            rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess);
    9801206            AssertRCReturn(rc, rc);
    9811207        }
     
    9941220
    9951221    RT_NOREF(pThisCC);
    996     Log7Func(("%s SAVE EXEC!!\n", INSTANCE(pThis)));
     1222    Log7Func(("%s SAVE EXEC!!\n", pThis->szInst));
    9971223
    9981224    pHlp->pfnSSMPutU64(     pSSM, pThis->fNegotiatedFeatures);
     
    10021228
    10031229    for (int idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
    1004         pHlp->pfnSSMPutBool(pSSM, pThis->afQueueAttached[idxQueue]);
     1230        pHlp->pfnSSMPutBool(pSSM, pThis->aQueues[idxQueue].fAttachedToVirtioCore);
    10051231
    10061232    /* Save config area */
     
    10531279
    10541280    Log7Func(("%s Device I/O activity quiesced: %s\n",
    1055         INSTANCE(pThis), virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor)));
     1281        pThis->szInst, virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor)));
    10561282
    10571283    virtioCoreR3VmStateChanged(&pThis->Virtio, pThisCC->enmQuiescingFor);
     
    10861312
    10871313    /* If already quiesced invoke async callback.  */
    1088     if (!ASMAtomicReadBool(&pThis->fLeafWantsRxBuffers))
     1314    if (!ASMAtomicReadBool(&pThis->fLeafWantsEmptyRxBufs))
    10891315        PDMDevHlpAsyncNotificationCompleted(pDevIns);
    10901316
     
    10981324{
    10991325    PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1100     Log7Func(("%s\n", INSTANCE(pThis)));
     1326    Log7Func(("%s\n", pThis->szInst));
    11011327    pThis->fResetting = true;
    11021328    virtioNetR3QuiesceDevice(pDevIns, kvirtIoVmStateChangedReset);
     
    11111337    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    11121338    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    1113     Log7Func(("%s\n", INSTANCE(pThis)));
     1339    Log7Func(("%s\n", pThis->szInst));
    11141340
    11151341    RT_NOREF2(pThis, pThisCC);
     
    11251351{
    11261352    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1127     Log7Func(("%s\n", INSTANCE(pThis)));
     1353    Log7Func(("%s\n", pThis->szInst));
    11281354    RT_NOREF(pThis);
    11291355    virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedPowerOff);
     
    11361362{
    11371363    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1138     Log7Func(("%s \n", INSTANCE(pThis)));
     1364    Log7Func(("%s \n", pThis->szInst));
    11391365    RT_NOREF(pThis);
    11401366    virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedSuspend);
     
    12131439void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn)
    12141440{
    1215     Log10Func(("%s\n", fOn ? "on" : "off"));
    12161441    if (fOn)
    12171442        pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1;
    12181443    else
    12191444        pThisR3->led.Actual.s.fWriting = fOn;
     1445}
     1446
     1447/*
     1448 * Returns true if VirtIO core and device are in a running and operational state
     1449 */
     1450DECLINLINE(bool) virtioNetIsOperational(PVIRTIONET pThis, PPDMDEVINS pDevIns)
     1451{
     1452    if (RT_LIKELY(pThis->fVirtioReady) && RT_LIKELY(!pThis->fQuiescing))
     1453    {
     1454        VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
     1455        if (RT_LIKELY(enmVMState == VMSTATE_RUNNING || enmVMState == VMSTATE_RUNNING_LS))
     1456            return true;
     1457    }
     1458    return false;
    12201459}
    12211460
     
    12311470 * @thread  RX
    12321471 */
    1233 static int virtioNetR3IsRxQueuePrimed(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint16_t idxRxQueue)
    1234 {
    1235 #define LOGPARAMS INSTANCE(pThis), VIRTQNAME(idxRxQueue)
    1236 
    1237     if (!pThis->fVirtioReady)
    1238     {
    1239         Log8Func(("%s %s VirtIO not ready (rc = VERR_NET_NO_BUFFER_SPACE)\n", LOGPARAMS));
    1240     }
    1241     else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, idxRxQueue))
    1242     {
    1243         Log8Func(("%s %s queue not enabled (rc = VERR_NET_NO_BUFFER_SPACE)\n", LOGPARAMS));
    1244     }
    1245     else if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, idxRxQueue))
    1246     {
    1247         Log8Func(("%s %s queue is empty (rc = VERR_NET_NO_BUFFER_SPACE)\n", LOGPARAMS));
    1248         virtioCoreQueueSetNotify(&pThis->Virtio, idxRxQueue, true);
    1249     }
     1472static int virtioNetR3CheckRxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETQUEUE pRxQueue)
     1473{
     1474    int rc = VERR_INVALID_STATE;
     1475
     1476    if (!virtioNetIsOperational(pThis, pDevIns))
     1477        Log8Func(("%s No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst));
     1478
     1479    else if (!virtioCoreIsQueueEnabled(&pThis->Virtio, pRxQueue->idx))
     1480        Log8Func(("%s No Rx bufs available. (%s not enabled)\n",  pThis->szInst, pRxQueue->szName));
     1481
     1482    else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxQueue->idx))
     1483        Log8Func(("%s No Rx bufs available. (%s empty)\n",  pThis->szInst, pRxQueue->szName));
     1484
    12501485    else
    12511486    {
    1252         Log8Func(("%s %s ready with available buffers\n", LOGPARAMS));
    1253         virtioCoreQueueSetNotify(&pThis->Virtio, idxRxQueue, false);
    1254         return VINF_SUCCESS;
    1255     }
    1256     return VERR_NET_NO_BUFFER_SPACE;
    1257 }
    1258 
    1259 
    1260 static bool virtioNetR3AreRxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis)
    1261 {
    1262     /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
    1263               selection algorithm feasible or even necessary to prevent starvation? */
     1487        Log8Func(("%s Empty guest buffers available in %s\n",  pThis->szInst,pRxQueue->szName));
     1488        rc = VINF_SUCCESS;
     1489    }
     1490    virtioCoreQueueNotifyEnable(&pThis->Virtio, pRxQueue->idx, rc == VERR_INVALID_STATE /* fEnable */);
     1491    return rc;
     1492}
     1493
     1494static bool virtioNetR3RxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETQUEUE *pRxQueue)
     1495{
    12641496    for (int idxQueuePair = 0; idxQueuePair < pThis->cVirtqPairs; idxQueuePair++)
    1265         if (RT_SUCCESS(virtioNetR3IsRxQueuePrimed(pDevIns, pThis, RXQIDX(idxQueuePair))))
     1497    {
     1498        PVIRTIONETQUEUE pThisRxQueue = &pThis->aQueues[RXQIDX(idxQueuePair)];
     1499        if (RT_SUCCESS(virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pThisRxQueue)))
     1500        {
     1501            if (pRxQueue)
     1502                *pRxQueue = pThisRxQueue;
    12661503            return true;
     1504        }
     1505    }
    12671506    return false;
    1268 }
    1269 /*
    1270  * Returns true if VirtIO core and device are in a running and operational state
    1271  */
    1272 DECLINLINE(bool) virtioNetIsOperational(PVIRTIONET pThis, PPDMDEVINS pDevIns)
    1273 {
    1274     if (!pThis->fVirtioReady)
    1275         return false;
    1276 
    1277     if (pThis->fQuiescing)
    1278         return false;
    1279 
    1280     VMSTATE enmVMState = PDMDevHlpVMState(pDevIns);
    1281     if (!RT_LIKELY(enmVMState == VMSTATE_RUNNING || enmVMState == VMSTATE_RUNNING_LS))
    1282         return false;
    1283 
    1284     return true;
    12851507}
    12861508
     
    12941516    PVIRTIONET   pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    12951517
    1296     if (virtioNetR3AreRxBufsAvail(pDevIns, pThis))
    1297     {
    1298             Log10Func(("%s Rx bufs now available, releasing waiter...\n", INSTANCE(pThis)));
    1299             return VINF_SUCCESS;
     1518    if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxQueue */))
     1519    {
     1520        Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
     1521        return VINF_SUCCESS;
    13001522    }
    13011523    if (!timeoutMs)
    13021524        return VERR_NET_NO_BUFFER_SPACE;
    13031525
    1304     LogFlowFunc(("%s timeoutMs=%u\n", INSTANCE(pThis), timeoutMs));
    1305 
    1306     ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, true);
     1526    LogFunc(("%s %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : ""));
     1527
     1528    ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, true);
    13071529    STAM_PROFILE_START(&pThis->StatRxOverflow, a);
    13081530
    13091531    do {
    1310         if (virtioNetR3AreRxBufsAvail(pDevIns, pThis))
     1532        if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxQueue */))
    13111533        {
    1312                 Log10Func(("%s Rx bufs now available, releasing waiter...\n", INSTANCE(pThis)));
    1313                 return VINF_SUCCESS;
     1534            Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst));
     1535            return VINF_SUCCESS;
    13141536        }
    1315         Log9Func(("%s Starved for guest Rx bufs, waiting %u ms ...\n",
    1316                  INSTANCE(pThis), timeoutMs));
     1537        Log9Func(("%s Starved for empty guest Rx bufs. Waiting...\n", pThis->szInst));
    13171538
    13181539        int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs);
    13191540
    13201541        if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED)
     1542        {
     1543            LogFunc(("Waken due to %s\n", rc == VERR_TIMEOUT ? "timeout" : "interrupted"));
    13211544            continue;
    1322 
    1323         if (RT_FAILURE(rc))
     1545        }
     1546        if (RT_FAILURE(rc)) {
     1547            LogFunc(("Waken due to failure %Rrc\n", rc));
    13241548            RTThreadSleep(1);
    1325 
     1549        }
     1550LogFunc(("\n\n\n********** WAKEN!!!!! ********\n\n\n"));
    13261551    } while (virtioNetIsOperational(pThis, pDevIns));
    13271552
    13281553    STAM_PROFILE_STOP(&pThis->StatRxOverflow, a);
    1329     ASMAtomicXchgBool(&pThis->fLeafWantsRxBuffers, false);
    1330 
    1331     Log7Func(("%s Wait for Rx buffers available was interrupted\n", INSTANCE(pThis)));
     1554    ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false);
     1555
     1556    Log7Func(("%s Wait for Rx buffers available was interrupted\n", pThis->szInst));
    13321557    return VERR_INTERRUPTED;
    13331558}
     
    14351660
    14361661        LogFunc(("%s node(%RTmac %s%s), pkt(%RTmac %s)",
    1437                  INSTANCE(pThis), pThis->virtioNetConfig.uMacAddress.au8,
     1662                 pThis->szInst, pThis->virtioNetConfig.uMacAddress.au8,
    14381663                 pThis->fPromiscuous ? "promiscuous" : "",
    14391664                 pThis->fAllMulticast ? " all-multicast" : "",
     
    14511676        && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF))
    14521677    {
    1453         Log11Func(("\n%s not our VLAN, returning false\n", INSTANCE(pThis)));
     1678        Log11Func(("\n%s not our VLAN, returning false\n", pThis->szInst));
    14541679        return false;
    14551680    }
     
    15051730                                       VIRTIONET_PKT_HDR_T *rxPktHdr, uint16_t cSegsAllocated,
    15061731                                       PRTSGBUF pVirtSegBufToGuest, PRTSGSEG paVirtSegsToGuest,
    1507                                        uint16_t idxRxQueue)
     1732                                       PVIRTIONETQUEUE pRxQueue)
    15081733{
    15091734    uint8_t fAddPktHdr = true;
    1510     RTGCPHYS gcPhysPktHdrNumBuffers = 0;
     1735    RTGCPHYS GCPhysPktHdrNumBuffers = 0;
    15111736    uint16_t cDescs;
    15121737    uint64_t uOffset;
     
    15151740        PVIRTIO_DESC_CHAIN_T pDescChain = NULL;
    15161741
    1517         int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX(idxRxQueue), &pDescChain, true);
     1742        int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, pRxQueue->idx, &pDescChain, true);
    15181743        AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc);
    15191744
     
    15261751        /* Length of first seg of guest Rx buf should never be less than sizeof(virtio_net_pkt_hdr).
    15271752         * Otherwise code has to become more complicated, e.g. locate & cache seg idx & offset of
    1528          * virtio_net_header.num_buffers, to defer updating (in gcPhys). Re-visit if needed */
     1753         * virtio_net_header.num_buffers, to defer updating (in GCPhys). Re-visit if needed */
    15291754
    15301755        AssertMsgReturnStmt(pDescChain->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONET_PKT_HDR_T),
     
    15491774                memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbHdr);
    15501775
    1551                 /* Calculate & cache addr of field to update after final value is known, in gcPhys mem */
    1552                 gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].gcPhys
     1776                /* Calculate & cache addr of field to update after final value is known, in GCPhys mem */
     1777                GCPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].GCPhys
    15531778                                         + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers);
    15541779                fAddPktHdr = false;
     
    15761801            Log7Func(("Send Rx pkt to guest...\n"));
    15771802            STAM_PROFILE_START(&pThis->StatReceiveStore, a);
    1578             virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, idxRxQueue,
    1579                                  pVirtSegBufToGuest, pDescChain, true);
     1803            virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, pRxQueue->idx,
     1804                                 pVirtSegBufToGuest, pDescChain, true /* fFence */);
    15801805            STAM_PROFILE_STOP(&pThis->StatReceiveStore, a);
    15811806
     
    15891814    if (uOffset < cb)
    15901815    {
    1591         LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", INSTANCE(pThis), cb));
     1816        LogFunc(("%s Packet did not fit into RX queue (packet size=%u)!\n", pThis->szInst, cb));
    15921817        return VERR_TOO_MUCH_DATA;
    15931818    }
     
    15951820    /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */
    15961821
    1597     int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs));
     1822    int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs));
    15981823    AssertMsgRCReturn(rc,
    15991824                  ("Failure updating descriptor count in pkt hdr in guest physical memory\n"),
    16001825                  rc);
    16011826
    1602     virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX(idxRxQueue));
     1827    virtioCoreQueueSync(pDevIns, &pThis->Virtio, pRxQueue->idx);
    16031828
    16041829    return VINF_SUCCESS;
     
    16221847 */
    16231848static int virtioNetR3HandleRxPacket(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    1624                                 const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso, uint16_t idxRxQueue)
     1849                                const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso, PVIRTIONETQUEUE pRxQueue)
    16251850{
    16261851    RT_NOREF(pThisCC);
    16271852
    1628     LogFunc(("%s (%RTmac) pGso %s\n", INSTANCE(pThis), pvBuf, pGso ? "present" : "not present"));
     1853    LogFunc(("%s (%RTmac) pGso %s\n", pThis->szInst, pvBuf, pGso ? "present" : "not present"));
    16291854    VIRTIONET_PKT_HDR_T rxPktHdr = { 0 };
    16301855
     
    16321857    {
    16331858        Log2Func(("%s gso type=%x cbPktHdrsTotal=%u cbPktHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    1634               INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal,
     1859              pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal,
    16351860              pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
    16361861
     
    16731898
    16741899    int rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pvBuf, cb, &rxPktHdr, cSegsAllocated,
    1675                                         pVirtSegBufToGuest, paVirtSegsToGuest, idxRxQueue);
     1900                                        pVirtSegBufToGuest, paVirtSegsToGuest, pRxQueue);
    16761901
    16771902    RTMemFree(paVirtSegsToGuest);
     
    16911916    PPDMDEVINS      pDevIns = pThisCC->pDevIns;
    16921917    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    1693 
     1918LogFunc(("\n"));
    16941919    if (!pThis->fVirtioReady)
    16951920    {
     
    17251950        if (!uFeatures)
    17261951        {
    1727             Log2Func(("%s GSO type (0x%x) not supported\n", INSTANCE(pThis), pGso->u8Type));
     1952            LogFunc(("%s GSO type (0x%x) not supported\n", pThis->szInst, pGso->u8Type));
    17281953            return VERR_NOT_SUPPORTED;
    17291954        }
    17301955    }
    17311956
    1732     Log10Func(("%s pvBuf=%p cb=%3u pGso=%p ...", INSTANCE(pThis), pvBuf, cb, pGso));
     1957    Log10Func(("%s pvBuf=%p cb=%3u pGso=%p ...\n", pThis->szInst, pvBuf, cb, pGso));
    17331958
    17341959    /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
     
    17371962    for (int idxQueuePair = 0; idxQueuePair < pThis->cVirtqPairs; idxQueuePair++)
    17381963    {
    1739         if (RT_SUCCESS(!virtioNetR3IsRxQueuePrimed(pDevIns, pThis, RXQIDX(idxQueuePair))))
     1964
     1965        PVIRTIONETQUEUE pRxQueue = &pThis->aQueues[RXQIDX(idxQueuePair)];
     1966        if (RT_SUCCESS(!virtioNetR3CheckRxBufsAvail(pDevIns, pThis, pRxQueue)))
    17401967        {
    17411968            /* Drop packets if VM is not running or cable is disconnected. */
     
    17491976            if (virtioNetR3AddressFilter(pThis, pvBuf, cb))
    17501977            {
    1751                 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, RXQIDX(idxQueuePair));
     1978                rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, pRxQueue);
    17521979                STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb);
    17531980            }
     
    17842011    }
    17852012    LogFunc(("%s Pulled %d/%d bytes from desc chain (%d bytes left)\n",
    1786              INSTANCE(pThis), cb - cbLim, cb, pDescChain->cbPhysSend));
     2013             pThis->szInst, cb - cbLim, cb, pDescChain->cbPhysSend));
    17872014    RT_NOREF(pThis);
    17882015}
     
    17922019{
    17932020
    1794 #define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s Setting %s=%d\n", INSTANCE(pThis), #fld, pThis->fld))
    1795 
    1796     LogFunc(("%s Processing CTRL Rx command\n", INSTANCE(pThis)));
     2021#define LOG_VIRTIONET_FLAG(fld) LogFunc(("%s Setting %s=%d\n", pThis->szInst, #fld, pThis->fld))
     2022
     2023    LogFunc(("%s Processing CTRL Rx command\n", pThis->szInst));
    17972024    RT_NOREF(pThis);
    17982025    switch(pCtrlPktHdr->uCmd)
     
    18662093                                  PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
    18672094{
    1868     LogFunc(("%s Processing CTRL MAC command\n", INSTANCE(pThis)));
     2095    LogFunc(("%s Processing CTRL MAC command\n", pThis->szInst));
    18692096
    18702097    RT_NOREF(pThisCC);
     
    18982125            virtioNetR3PullChain(pDevIns, pThis, pDescChain, &cMacs, sizeof(cMacs));
    18992126            cbRemaining -= sizeof(cMacs);
    1900             Log7Func(("%s Guest provided %d unicast MAC Table entries\n", INSTANCE(pThis), cMacs));
     2127            Log7Func(("%s Guest provided %d unicast MAC Table entries\n", pThis->szInst, cMacs));
    19012128            if (cMacs)
    19022129            {
     
    19122139            virtioNetR3PullChain(pDevIns, pThis, pDescChain, &cMacs, sizeof(cMacs));
    19132140            cbRemaining -= sizeof(cMacs);
    1914             Log10Func(("%s Guest provided %d multicast MAC Table entries\n", INSTANCE(pThis), cMacs));
     2141            Log10Func(("%s Guest provided %d multicast MAC Table entries\n", pThis->szInst, cMacs));
    19152142            if (cMacs)
    19162143            {
     
    19232150
    19242151#ifdef LOG_ENABLED
    1925             LogFunc(("%s unicast MACs:\n", INSTANCE(pThis)));
     2152            LogFunc(("%s unicast MACs:\n", pThis->szInst));
    19262153            for(unsigned i = 0; i < cMacs; i++)
    19272154                LogFunc(("         %RTmac\n", &pThis->aMacUnicastFilter[i]));
    19282155
    1929             LogFunc(("%s multicast MACs:\n", INSTANCE(pThis)));
     2156            LogFunc(("%s multicast MACs:\n", pThis->szInst));
    19302157            for(unsigned i = 0; i < cMacs; i++)
    19312158                LogFunc(("         %RTmac\n", &pThis->aMacMulticastFilter[i]));
     
    19392166                                   PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain)
    19402167{
    1941     LogFunc(("%s Processing CTRL VLAN command\n", INSTANCE(pThis)));
     2168    LogFunc(("%s Processing CTRL VLAN command\n", pThis->szInst));
    19422169
    19432170    RT_NOREF(pThisCC);
     
    19492176    virtioNetR3PullChain(pDevIns, pThis, pDescChain, &uVlanId, sizeof(uVlanId));
    19502177    AssertMsgReturn(uVlanId > VIRTIONET_MAX_VLAN_ID,
    1951         ("%s VLAN ID out of range (VLAN ID=%u)\n", INSTANCE(pThis), uVlanId), VIRTIONET_ERROR);
    1952     LogFunc(("%s uCommand=%u VLAN ID=%u\n", INSTANCE(pThis), pCtrlPktHdr->uCmd, uVlanId));
     2178        ("%s VLAN ID out of range (VLAN ID=%u)\n", pThis->szInst, uVlanId), VIRTIONET_ERROR);
     2179    LogFunc(("%s uCommand=%u VLAN ID=%u\n", pThis->szInst, pCtrlPktHdr->uCmd, uVlanId));
    19532180    switch (pCtrlPktHdr->uCmd)
    19542181    {
     
    19682195                            PVIRTIO_DESC_CHAIN_T pDescChain)
    19692196{
    1970     LogFunc(("%s Received CTRL packet from guest\n", INSTANCE(pThis)));
     2197    LogFunc(("%s Received CTRL packet from guest\n", pThis->szInst));
    19712198
    19722199    if (pDescChain->cbPhysSend < 2)
    19732200    {
    1974         LogFunc(("%s CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", INSTANCE(pThis)));
     2201        LogFunc(("%s CTRL packet from guest driver incomplete. Skipping ctrl cmd\n", pThis->szInst));
    19752202        return;
    19762203    }
    19772204    else if (pDescChain->cbPhysReturn < sizeof(VIRTIONET_CTRL_HDR_T_ACK))
    19782205    {
    1979         LogFunc(("%s Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", INSTANCE(pThis)));
     2206        LogFunc(("%s Guest driver didn't allocate memory to receive ctrl pkt ACK. Skipping ctrl cmd\n", pThis->szInst));
    19802207        return;
    19812208    }
     
    19942221                         RT_MIN(pDescChain->cbPhysSend, sizeof(VIRTIONET_CTRL_HDR_T)));
    19952222
    1996     Log7Func(("%s CTRL COMMAND: class=%d command=%d\n", INSTANCE(pThis), pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
     2223    Log7Func(("%s CTRL COMMAND: class=%d command=%d\n", pThis->szInst, pCtrlPktHdr->uClass, pCtrlPktHdr->uCmd));
    19972224
    19982225    uint8_t uAck;
     
    20132240            {
    20142241                LogFunc(("%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE.\n"
    2015                          "VIRTIO_F_STATUS or VIRTIO_F_GUEST_ANNOUNCE feature not enabled\n", INSTANCE(pThis)));
     2242                         "VIRTIO_F_STATUS or VIRTIO_F_GUEST_ANNOUNCE feature not enabled\n", pThis->szInst));
    20162243                break;
    20172244            }
    20182245            if (pCtrlPktHdr->uCmd != VIRTIONET_CTRL_ANNOUNCE_ACK)
    20192246            {
    2020                 LogFunc(("%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", INSTANCE(pThis)));
     2247                LogFunc(("%s Ignoring CTRL class VIRTIONET_CTRL_ANNOUNCE. Unrecognized uCmd\n", pThis->szInst));
    20212248                break;
    20222249            }
    20232250            pThis->virtioNetConfig.uStatus &= ~VIRTIONET_F_ANNOUNCE;
    2024             Log7Func(("%s Clearing VIRTIONET_F_ANNOUNCE in config status\n", INSTANCE(pThis)));
     2251            Log7Func(("%s Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst));
    20252252            break;
    20262253
     
    20552282    RTSgBufInit(pReturnSegBuf, paReturnSegs, cSegs);
    20562283
    2057     virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pReturnSegBuf, pDescChain, true);
     2284    virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pReturnSegBuf, pDescChain, true /* fFence */);
    20582285    virtioCoreQueueSync(pDevIns, &pThis->Virtio, CTRLQIDX);
    20592286
     
    20652292
    20662293    LogFunc(("%s Finished processing CTRL command with status %s\n",
    2067              INSTANCE(pThis), uAck == VIRTIONET_OK ? "VIRTIONET_OK" : "VIRTIONET_ERROR"));
     2294             pThis->szInst, uAck == VIRTIONET_OK ? "VIRTIONET_OK" : "VIRTIONET_ERROR"));
    20682295}
    20692296
     
    20742301        return rc;
    20752302
    2076     Log(("virtio-net: header (flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x) cbFrame=%d\n",
     2303    LogFunc(("pktHdr (flags=%x gso-type=%x len=%x gso-size=%x Chksum-start=%x Chksum-offset=%x) cbFrame=%d\n",
    20772304          pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen,
    20782305          pPktHdr->uGsoSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbFrame));
     
    21282355        {
    21292356            Log4Func(("%s HdrLen before adjustment %d.\n",
    2130                   INSTANCE(pThis), pGso->cbHdrsTotal));
     2357                  pThis->szInst, pGso->cbHdrsTotal));
    21312358            switch (pGso->u8Type)
    21322359            {
     
    21462373            ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg   = pGso->cbHdrsSeg;
    21472374            Log4Func(("%s adjusted HdrLen to %d.\n",
    2148                   INSTANCE(pThis), pGso->cbHdrsTotal));
     2375                  pThis->szInst, pGso->cbHdrsTotal));
    21492376        }
    21502377        Log2Func(("%s gso type=%x cbHdrsTotal=%u cbHdrsSeg=%u mss=%u off1=0x%x off2=0x%x\n",
    2151                   INSTANCE(pThis), pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg,
     2378                  pThis->szInst, pGso->u8Type, pGso->cbHdrsTotal, pGso->cbHdrsSeg,
    21522379                  pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2));
    21532380        STAM_REL_COUNTER_INC(&pThis->StatTransmitGSO);
     
    21632390    }
    21642391
    2165     return pThisCC->pDrv->pfnSendBuf(pThisCC->pDrv, pSgBuf, false);
     2392    return pThisCC->pDrv->pfnSendBuf(pThisCC->pDrv, pSgBuf, true /* fOnWorkerThread */);
    21662393}
    21672394
    21682395static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    2169                                          uint16_t idxTxQueue, bool fOnWorkerThread)
     2396                                         PVIRTIONETQUEUE pTxQueue, bool fOnWorkerThread)
    21702397{
    21712398
     
    21832410    {
    21842411        LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x).\n",
    2185                 INSTANCE(pThis), pThis->virtioNetConfig.uStatus));
     2412                pThis->szInst, pThis->virtioNetConfig.uStatus));
    21862413        return;
    21872414    }
     
    21892416    if (!pThis->fCableConnected)
    21902417    {
    2191         Log(("%s Ignoring transmit requests while cable is disconnected.\n", INSTANCE(pThis)));
     2418        Log(("%s Ignoring transmit requests while cable is disconnected.\n", pThis->szInst));
    21922419        return;
    21932420    }
     
    22052432    }
    22062433
    2207     int cPkts = virtioCoreR3QueuePendingCount(pVirtio->pDevInsR3, pVirtio, idxTxQueue);
     2434    int cPkts = virtioCoreQueueAvailCount(pVirtio->pDevInsR3, pVirtio, pTxQueue->idx);
    22082435    if (!cPkts)
    22092436    {
    2210         LogFunc(("%s No packets to send found on %s\n", INSTANCE(pThis), VIRTQNAME(idxTxQueue)));
     2437        LogFunc(("%s No packets to send found on %s\n", pThis->szInst, pTxQueue->szName));
    22112438
    22122439        if (pDrv)
     
    22162443        return;
    22172444    }
    2218     LogFunc(("%s About to transmit %d pending packets\n", INSTANCE(pThis), cPkts));
     2445    LogFunc(("%s About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's'));
    22192446
    22202447    virtioNetR3SetWriteLed(pThisCC, true);
     
    22222449    int rc;
    22232450    PVIRTIO_DESC_CHAIN_T pDescChain = NULL;
    2224     while ((rc = virtioCoreR3QueuePeek(pVirtio->pDevInsR3, pVirtio, idxTxQueue, &pDescChain)) == VINF_SUCCESS)
    2225     {
    2226         Log10Func(("%s fetched descriptor chain from %s\n", INSTANCE(pThis), VIRTQNAME(idxTxQueue)));
     2451    while ((rc = virtioCoreR3QueuePeek(pVirtio->pDevInsR3, pVirtio, pTxQueue->idx, &pDescChain)) == VINF_SUCCESS)
     2452    {
     2453        Log10Func(("%s fetched descriptor chain from %s\n", pThis->szInst, pTxQueue->szName));
    22272454
    22282455        PVIRTIOSGBUF pSgPhysSend = pDescChain->pSgPhysSend;
     
    22392466            uSize +=  paSegsFromGuest[i].cbSeg;
    22402467
    2241         Log5Func(("%s complete frame is %u bytes.\n", INSTANCE(pThis), uSize));
     2468        Log5Func(("%s complete frame is %u bytes.\n", pThis->szInst, uSize));
    22422469        Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE);
    22432470
     
    22482475        if (pThisCC->pDrv)
    22492476        {
    2250             PDMNETWORKGSO  Gso;
    2251             PPDMNETWORKGSO pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);
    22522477            uint64_t uOffset;
     2478
     2479            uSize -= sizeof(PktHdr);
     2480            rc = virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].GCPhys, &PktHdr, uSize);
     2481            if (RT_FAILURE(rc))
     2482                return;
     2483            virtioCoreSgBufAdvance(pSgPhysSend, sizeof(PktHdr));
     2484
     2485            PDMNETWORKGSO  Gso, *pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);
    22532486
    22542487            PPDMSCATTERGATHER pSgBufToPdmLeafDevice;
     
    22582491                STAM_REL_COUNTER_INC(&pThis->StatTransmitPackets);
    22592492                STAM_PROFILE_START(&pThis->StatTransmitSend, a);
    2260 
    2261                 uSize -= sizeof(PktHdr);
    2262                 rc = virtioNetR3ReadHeader(pDevIns, paSegsFromGuest[0].gcPhys, &PktHdr, uSize);
    2263                 if (RT_FAILURE(rc))
    2264                     return;
    2265                 virtioCoreSgBufAdvance(pSgPhysSend, sizeof(PktHdr));
    22662493
    22672494                size_t cbCopied = 0;
     
    22722499                {
    22732500                    PVIRTIOSGSEG paSeg  = &pSgPhysSend->paSegs[pSgPhysSend->idxSeg];
    2274                     uint64_t srcSgStart = (uint64_t)paSeg->gcPhys;
     2501                    uint64_t srcSgStart = (uint64_t)paSeg->GCPhys;
    22752502                    uint64_t srcSgLen   = (uint64_t)paSeg->cbSeg;
    2276                     uint64_t srcSgCur   = (uint64_t)pSgPhysSend->gcPhysCur;
     2503                    uint64_t srcSgCur   = (uint64_t)pSgPhysSend->GCPhysCur;
    22772504                    cbCopied = RT_MIN((uint64_t)cbRemain, srcSgLen - (srcSgCur - srcSgStart));
    22782505                    PDMDevHlpPCIPhysRead(pDevIns,
    2279                                          (RTGCPHYS)pSgPhysSend->gcPhysCur,
     2506                                         (RTGCPHYS)pSgPhysSend->GCPhysCur,
    22802507                                         ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset, cbCopied);
    22812508                    virtioCoreSgBufAdvance(pSgPhysSend, cbCopied);
     
    22912518                if (RT_FAILURE(rc))
    22922519                {
    2293                     LogFunc(("%s Failed to transmit frame, rc = %Rrc\n", INSTANCE(pThis), rc));
     2520                    LogFunc(("%s Failed to transmit frame, rc = %Rrc\n", pThis->szInst, rc));
    22942521                    STAM_PROFILE_STOP(&pThis->StatTransmitSend, a);
    22952522                    STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a);
     
    23082535
    23092536            /* Remove this descriptor chain from the available ring */
    2310             virtioCoreR3QueueSkip(pVirtio, idxTxQueue);
     2537            virtioCoreR3QueueSkip(pVirtio, pTxQueue->idx);
    23112538
    23122539            /* No data to return to guest, but call is needed put elem (e.g. desc chain) on used ring */
    2313             virtioCoreR3QueuePut(pVirtio->pDevInsR3, pVirtio, idxTxQueue, NULL, pDescChain, false);
     2540            virtioCoreR3QueuePut(pVirtio->pDevInsR3, pVirtio, pTxQueue->idx, NULL, pDescChain, true /* fFence */);
    23142541
    23152542            /* Update used ring idx and notify guest that we've transmitted the data it sent */
    2316             virtioCoreQueueSync(pVirtio->pDevInsR3, pVirtio, idxTxQueue);
     2543            virtioCoreQueueSync(pVirtio->pDevInsR3, pVirtio, pTxQueue->idx);
    23172544        }
    23182545
     
    23372564    PPDMDEVINS      pDevIns = pThisCC->pDevIns;
    23382565    PVIRTIONET      pThis   = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
    2339 
     2566    PVIRTIONETQUEUE pTxQueue  = &pThis->aQueues[TXQIDX(0)];
    23402567    STAM_COUNTER_INC(&pThis->StatTransmitByNetwork);
    23412568
    23422569    /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue
    23432570          selection algorithm feasible or even necessary */
    2344     virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, TXQIDX(0), false /*fOnWorkerThread*/);
    2345 }
    2346 
    2347 /**
    2348  * @callback_method_impl{FNPDMTHREADDEV}
    2349  */
    2350 static DECLCALLBACK(int) virtioNetR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
    2351 {
    2352     PVIRTIONET         pThis     = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
    2353     PVIRTIONETCC       pThisCC   = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    2354     uint16_t const     idxWorker = (uint16_t)(uintptr_t)pThread->pvUser;
    2355     PVIRTIONETWORKER   pWorker   = &pThis->aWorkers[idxWorker];
    2356     PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxWorker];
    2357     uint16_t const     idxQueue  = pWorkerR3->idxQueue;
    2358 
    2359     if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
    2360     {
    2361         return VINF_SUCCESS;
    2362     }
    2363     LogFunc(("%s worker thread started for %s\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    2364     virtioCoreQueueSetNotify(&pThis->Virtio, idxQueue, false);
    2365     while (pThread->enmState == PDMTHREADSTATE_RUNNING)
    2366     {
    2367         if (virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, idxQueue))
    2368         {
    2369             /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */
    2370             virtioCoreQueueSetNotify(&pThis->Virtio, idxQueue, true);
    2371             ASMAtomicWriteBool(&pWorker->fSleeping, true);
    2372             bool fNotificationSent = ASMAtomicXchgBool(&pWorker->fNotified, false);
    2373             if (!fNotificationSent)
    2374             {
    2375                 Log10Func(("%s %s worker sleeping...\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    2376                 Assert(ASMAtomicReadBool(&pWorker->fSleeping));
    2377                 int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pWorker->hEvtProcess, RT_INDEFINITE_WAIT);
    2378                 STAM_COUNTER_INC(&pThis->StatTransmitByThread);
    2379                 AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
    2380                 if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
    2381                     return VINF_SUCCESS;
    2382                 if (rc == VERR_INTERRUPTED)
    2383                 {
    2384                     virtioCoreQueueSetNotify(&pThis->Virtio, idxQueue, false);
    2385                     continue;
    2386                 }
    2387                 Log10Func(("%s %s worker woken\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    2388                 ASMAtomicWriteBool(&pWorker->fNotified, false);
    2389             }
    2390             ASMAtomicWriteBool(&pWorker->fSleeping, false);
    2391             virtioCoreQueueSetNotify(&pThis->Virtio, idxQueue, false);
    2392         }
    2393 
    2394         /* Dispatch to the handler for the queue this worker is set up to drive */
    2395 
    2396         if (!pThisCC->fQuiescing)
    2397         {
    2398              if (IS_CTRL_QUEUE(idxQueue))
    2399              {
    2400                  Log10Func(("%s fetching next descriptor chain from %s\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    2401                  PVIRTIO_DESC_CHAIN_T pDescChain = NULL;
    2402                  int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, idxQueue, &pDescChain, true);
    2403                  if (rc == VERR_NOT_AVAILABLE)
    2404                  {
    2405                     Log10Func(("%s Nothing found in %s\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));
    2406                     continue;
    2407                  }
    2408                  virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain);
    2409                  virtioCoreR3DescChainRelease(&pThis->Virtio, pDescChain);
    2410              }
    2411              else if (IS_TX_QUEUE(idxQueue))
    2412              {
    2413                  Log10Func(("%s Notified of data to transmit\n", INSTANCE(pThis)));
    2414                  virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC,
    2415                                                    idxQueue, false /* fOnWorkerThread */);
    2416              }
    2417 
    2418              /* Rx queues aren't handled by our worker threads. Instead, the PDM network
    2419               * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback,
    2420               * which waits until notified directly by virtioNetQueueNotified()
    2421               * that guest IN buffers have been added to receive virt queue.
    2422               */
    2423         }
    2424     }
    2425     return VINF_SUCCESS;
    2426 }
     2571    virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxQueue, true /*fOnWorkerThread*/);
     2572}
     2573
    24272574
    24282575#ifdef USING_CRITICAL_SECTION
     
    24312578    RT_NOREF(pDevIns, pThis, rcBusy);
    24322579    /* Original DevVirtioNet uses CS in attach/detach/link-up timer/tx timer/transmit */
    2433     LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", INSTANCE(pThis)));
     2580    LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", pThis->szInst));
    24342581    return VINF_SUCCESS;
    24352582}
     
    24382585{
    24392586    RT_NOREF(pDevIns, pThis);
    2440     LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", INSTANCE(pThis)));
     2587    LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", pThis->szInst));
    24412588}
    24422589#endif /* USING_CRITICAL_SECTION */
     
    24592606    LEAVE_CRITICAL_SECTION;
    24602607
    2461     LogFunc(("%s Link is up\n", INSTANCE(pThis)));
     2608    LogFunc(("%s Link is up\n", pThis->szInst));
    24622609
    24632610    if (pThisCC->pDrv)
     
    24882635        AssertRC(rc);
    24892636
    2490         LogFunc(("%s Link is down temporarily\n", INSTANCE(pThis)));
    2491     }
    2492 }
    2493 
    2494 /**
    2495  * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
    2496  */
    2497 static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface)
    2498 {
    2499     PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig);
    2500     PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
    2501 
    2502     return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN;
     2637        LogFunc(("%s Link is down temporarily\n", pThis->szInst));
     2638    }
    25032639}
    25042640
     
    25172653    if (LogIs7Enabled())
    25182654    {
    2519         LogFunc(("%s", INSTANCE(pThis)));
     2655        LogFunc(("%s", pThis->szInst));
    25202656        switch(enmState)
    25212657        {
     
    25512687        if (fCachedLinkIsUp)
    25522688        {
    2553             Log(("%s Link is up\n", INSTANCE(pThis)));
     2689            Log(("%s Link is up\n", pThis->szInst));
    25542690            pThis->fCableConnected = true;
    25552691            SET_LINK_UP(pThis);
     
    25602696            /* The link was brought down explicitly, make sure it won't come up by timer.  */
    25612697            PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer);
    2562             Log(("%s Link is down\n", INSTANCE(pThis)));
     2698            Log(("%s Link is down\n", pThis->szInst));
    25632699            pThis->fCableConnected = false;
    25642700            SET_LINK_DOWN(pThis);
     
    25702706    return VINF_SUCCESS;
    25712707}
     2708/**
     2709 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState}
     2710 */
     2711static DECLCALLBACK(PDMNETWORKLINKSTATE) virtioNetR3NetworkConfig_GetLinkState(PPDMINETWORKCONFIG pInterface)
     2712{
     2713    PVIRTIONETCC pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, INetworkConfig);
     2714    PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET);
     2715
     2716    return IS_LINK_UP(pThis) ? PDMNETWORKLINKSTATE_UP : PDMNETWORKLINKSTATE_DOWN;
     2717}
    25722718
    25732719static int virtioNetR3DestroyWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    25742720{
    2575     Log10Func(("%s\n", INSTANCE(pThis)));
     2721    Log10Func(("%s\n", pThis->szInst));
    25762722    int rc = VINF_SUCCESS;
    25772723    for (unsigned idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++)
    25782724    {
    2579         PVIRTIONETWORKER pWorker = &pThis->aWorkers[idxWorker];
     2725        PVIRTIONETWORKER   pWorker   = &pThis->aWorkers[idxWorker];
     2726        PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxWorker];
     2727
    25802728        if (pWorker->hEvtProcess != NIL_SUPSEMEVENT)
    25812729        {
     
    25832731            pWorker->hEvtProcess = NIL_SUPSEMEVENT;
    25842732        }
    2585         if (pThisCC->aWorkers[idxWorker].pThread)
     2733        if (pWorkerR3->pThread)
    25862734        {
    25872735            int rcThread;
    2588             rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[idxWorker].pThread, &rcThread);
     2736            rc = PDMDevHlpThreadDestroy(pDevIns, pWorkerR3->pThread, &rcThread);
    25892737            if (RT_FAILURE(rc) || RT_FAILURE(rcThread))
    25902738                AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread));
    2591            pThisCC->aWorkers[idxWorker].pThread = NULL;
     2739            pWorkerR3->pThread = NULL;
    25922740        }
    25932741    }
     
    25952743}
    25962744
    2597 static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC,
    2598                                             uint16_t idxWorker, uint16_t idxQueue)
    2599 {
    2600     Log10Func(("%s\n", INSTANCE(pThis)));
    2601     int rc = VINF_SUCCESS;
    2602     rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->aWorkers[idxWorker].hEvtProcess);
     2745static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint16_t idxWorker,
     2746                                            PVIRTIONETWORKER pWorker, PVIRTIONETWORKERR3 pWorkerR3,
     2747                                            PVIRTIONETQUEUE pQueue)
     2748{
     2749    Log10Func(("%s\n", pThis->szInst));
     2750
     2751    int rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pWorker->hEvtProcess);
    26032752
    26042753    if (RT_FAILURE(rc))
     
    26062755                                   N_("DevVirtioNET: Failed to create SUP event semaphore"));
    26072756
    2608     LogFunc(("creating thread, idxWorker=%d, idxQueue=%d\n", idxWorker, idxQueue));
    2609     rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->aWorkers[idxWorker].pThread,
    2610                                (void *)(uintptr_t)idxWorker, virtioNetR3WorkerThread,
    2611                                virtioNetR3WakeupWorker, 0, RTTHREADTYPE_IO, VIRTQNAME(idxQueue));
    2612     if (rc != VINF_SUCCESS)
    2613     {
    2614         LogRel(("Error creating thread for Virtual Queue %s: %Rrc\n", VIRTQNAME(idxQueue), rc));
    2615         return rc;
    2616     }
    2617     pThisCC->aWorkers[idxWorker].idxQueue = idxQueue;
    2618     pThis->afQueueAttached[idxQueue] = true;
     2757    LogFunc(("creating thread for queue %s\n", pQueue->szName));
     2758
     2759    rc = PDMDevHlpThreadCreate(pDevIns, &pWorkerR3->pThread,
     2760                               (void *)pWorker, virtioNetR3WorkerThread,
     2761                               virtioNetR3WakeupWorker, 0, RTTHREADTYPE_IO, pQueue->szName);
     2762    if (RT_FAILURE(rc))
     2763        return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
     2764                                   N_("Error creating thread for Virtual Queue %s\n"), pQueue->idx);
     2765
     2766    pWorker->pQueue    = pWorkerR3->pQueue = pQueue;
     2767    pWorker->idx       = pWorkerR3->idx    = idxWorker;
     2768    pQueue->pWorker    = pWorker;
     2769    pQueue->pWorkerR3  = pWorkerR3;
     2770    pWorker->fAssigned = true;
     2771
     2772    LogFunc(("%s pThread: %p\n", pQueue->szName, pWorkerR3->pThread));
     2773
    26192774    return rc;
    26202775}
     
    26222777static int virtioNetR3CreateWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC)
    26232778{
    2624     Log10Func(("%s\n", INSTANCE(pThis)));
    2625 
    2626     int rc;
    2627     uint16_t idxWorker = 0;
    2628     for (uint16_t idxQueuePair = 0; idxQueuePair < pThis->cVirtqPairs; idxQueuePair++)
    2629     {
    2630         rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, pThisCC, idxWorker, TXQIDX(idxQueuePair));
     2779
     2780#define CTRLWIDX 0 /* First worker is for the control queue */
     2781
     2782    Log10Func(("%s\n", pThis->szInst));
     2783
     2784    PVIRTIONETQUEUE pCtlQueue = &pThis->aQueues[CTRLQIDX];
     2785    int rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, CTRLQIDX /* idxWorker */,
     2786                                              &pThis->aWorkers[CTRLWIDX], &pThisCC->aWorkers[CTRLWIDX], pCtlQueue);
     2787    AssertRCReturn(rc, rc);
     2788
     2789    pCtlQueue->fHasWorker = true;
     2790
     2791    uint16_t idxWorker = CTRLWIDX + 1;
     2792    for (uint16_t idxQueuePair = 0; idxQueuePair < pThis->cVirtqPairs; idxQueuePair++, idxWorker++)
     2793    {
     2794        PVIRTIONETQUEUE pTxQueue = &pThis->aQueues[TXQIDX(idxQueuePair)];
     2795        PVIRTIONETQUEUE pRxQueue = &pThis->aQueues[RXQIDX(idxQueuePair)];
     2796
     2797        rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, idxWorker, &pThis->aWorkers[idxWorker],
     2798                                              &pThisCC->aWorkers[idxWorker], pTxQueue);
    26312799        AssertRCReturn(rc, rc);
    2632         idxWorker++;
    2633     }
    2634     rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, pThisCC, idxWorker, CTRLQIDX);
    2635     pThis->cWorkers = idxWorker + 1;
     2800
     2801        pTxQueue->fHasWorker = true;
     2802        pRxQueue->fHasWorker = false;
     2803    }
     2804    pThis->cWorkers = pThis->cVirtqPairs + 1;
    26362805    return rc;
    26372806}
     2807
     2808/**
     2809 * @callback_method_impl{FNPDMTHREADDEV}
     2810 */
     2811static DECLCALLBACK(int) virtioNetR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread)
     2812{
     2813    PVIRTIONET         pThis     = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);
     2814    PVIRTIONETCC       pThisCC   = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
     2815    PVIRTIONETWORKER   pWorker   = (PVIRTIONETWORKER)pThread->pvUser;
     2816    PVIRTIONETQUEUE    pQueue    = pWorker->pQueue;
     2817
     2818    if (pThread->enmState == PDMTHREADSTATE_INITIALIZING)
     2819        return VINF_SUCCESS;
     2820
     2821    LogFunc(("%s worker thread started for %s\n", pThis->szInst, pQueue->szName));
     2822
     2823 /** @todo Race w/guest enabling/disabling guest notifications cyclically.
     2824           that causes the controlq activity to hang sporadically. See BugRef #8651, Comment #82 */
     2825
     2826    virtioCoreQueueNotifyEnable(&pThis->Virtio, pQueue->idx, true /* fEnable */);
     2827
     2828    while (pThread->enmState == PDMTHREADSTATE_RUNNING)
     2829    {
     2830        if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pQueue->idx))
     2831        {
     2832            /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */
     2833            ASMAtomicWriteBool(&pWorker->fSleeping, true);
     2834            bool fNotificationSent = ASMAtomicXchgBool(&pWorker->fNotified, false);
     2835            if (!fNotificationSent)
     2836            {
     2837                Log10Func(("%s %s worker sleeping...\n\n", pThis->szInst, pQueue->szName));
     2838                Assert(ASMAtomicReadBool(&pWorker->fSleeping));
     2839                int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pWorker->hEvtProcess, RT_INDEFINITE_WAIT);
     2840                STAM_COUNTER_INC(&pThis->StatTransmitByThread);
     2841                AssertLogRelMsgReturn(RT_SUCCESS(rc) || rc == VERR_INTERRUPTED, ("%Rrc\n", rc), rc);
     2842                if (RT_UNLIKELY(pThread->enmState != PDMTHREADSTATE_RUNNING))
     2843                    return VINF_SUCCESS;
     2844                if (rc == VERR_INTERRUPTED)
     2845                    continue;
     2846               ASMAtomicWriteBool(&pWorker->fNotified, false);
     2847            }
     2848            ASMAtomicWriteBool(&pWorker->fSleeping, false);
     2849        }
     2850
     2851        /* Dispatch to the handler for the queue this worker is set up to drive */
     2852
     2853        if (!pThisCC->fQuiescing)
     2854        {
     2855             if (pQueue->fCtlQueue)
     2856             {
     2857                 Log10Func(("%s %s worker woken. Fetching desc chain\n", pThis->szInst, pQueue->szName));
     2858                 PVIRTIO_DESC_CHAIN_T pDescChain = NULL;
     2859                 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, pQueue->idx, &pDescChain, true);
     2860                 if (rc == VERR_NOT_AVAILABLE)
     2861                 {
     2862                    Log10Func(("%s %s worker woken. Nothing found in queue/n", pThis->szInst, pQueue->szName));
     2863                    continue;
     2864                 }
     2865                 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pDescChain);
     2866                 virtioCoreR3DescChainRelease(&pThis->Virtio, pDescChain);
     2867             }
     2868             else /* Must be Tx queue */
     2869             {
     2870                 Log10Func(("%s %s worker woken. Queue has data to transmit\n",  pThis->szInst, pQueue->szName));
     2871                 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pQueue, false /* fOnWorkerThread */);
     2872             }
     2873
     2874             /* Rx queues aren't handled by our worker threads. Instead, the PDM network
     2875              * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback,
     2876              * which waits until notified directly by virtioNetQueueNotified()
     2877              * that guest IN buffers have been added to receive virt queue.
     2878              */
     2879        }
     2880    }
     2881    Log10(("%s %s worker thread exiting\n", pThis->szInst, pQueue->szName));
     2882    return VINF_SUCCESS;
     2883}
     2884
    26382885/**
    26392886 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged}
     
    26492896    {
    26502897        LogFunc(("%s VirtIO ready\n-----------------------------------------------------------------------------------------\n",
    2651                  INSTANCE(pThis)));
     2898                 pThis->szInst));
     2899
     2900        pThis->fNegotiatedFeatures = virtioCoreGetAcceptedFeatures(pVirtio);
     2901
     2902#ifdef LOG_ENABLED
     2903        virtioCorePrintFeatures(pVirtio, NULL);
     2904        virtioNetPrintFeatures(pThis, NULL);
     2905#endif
     2906
    26522907        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
    26532908
    2654         pThis->fResetting    = false;
    2655         pThisCC->fQuiescing  = false;
    2656         pThis->fNegotiatedFeatures = virtioCoreGetAcceptedFeatures(pVirtio);
    2657 #ifdef LOG_ENABLED
    2658         virtioPrintFeatures(pVirtio);
    2659         virtioNetPrintFeatures(pThis);
    2660 #endif
     2909        pThis->fResetting = false;
     2910        pThisCC->fQuiescing = false;
     2911
    26612912        for (unsigned idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
    26622913        {
    2663             (void) virtioCoreR3QueueAttach(&pThis->Virtio, idxQueue, VIRTQNAME(idxQueue));
    2664             pThis->afQueueAttached[idxQueue] = true;
    2665             if (virtioCoreQueueIsEmpty(pThisCC->pDevIns, &pThis->Virtio, idxQueue))
    2666                 virtioCoreQueueSetNotify(&pThis->Virtio, idxQueue, true);
     2914            PVIRTIONETQUEUE pQueue = &pThis->aQueues[idxQueue];
     2915            pQueue->idx = idxQueue;
     2916            (void) virtioCoreR3QueueAttach(&pThis->Virtio, pQueue->idx, pQueue->szName);
     2917            pQueue->fAttachedToVirtioCore = true;
     2918            if (IS_VIRTQ_EMPTY(pThisCC->pDevIns, &pThis->Virtio, pQueue->idx))
     2919                virtioCoreQueueNotifyEnable(&pThis->Virtio, pQueue->idx, true /* fEnable */);
    26672920        }
    26682921    }
    26692922    else
    26702923    {
    2671         LogFunc(("%s VirtIO is resetting\n", INSTANCE(pThis)));
     2924        LogFunc(("%s VirtIO is resetting\n", pThis->szInst));
    26722925
    26732926        pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0;
    2674         Log7Func(("%s Link is %s\n", INSTANCE(pThis), pThis->fCableConnected ? "up" : "down"));
     2927        Log7Func(("%s Link is %s\n", pThis->szInst, pThis->fCableConnected ? "up" : "down"));
    26752928
    26762929        pThis->fPromiscuous         = true;
     
    26902943        pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true);
    26912944
    2692         for (unsigned idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
    2693             pThis->afQueueAttached[idxQueue] = false;
     2945        for (uint16_t idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)
     2946            pThis->aQueues[idxQueue].fAttachedToVirtioCore = false;
    26942947    }
    26952948}
     
    27092962    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    27102963
    2711     Log7Func(("%s\n", INSTANCE(pThis)));
     2964    Log7Func(("%s\n", pThis->szInst));
    27122965    AssertLogRelReturnVoid(iLUN == 0);
    27132966
     
    27372990    RT_NOREF(fFlags);
    27382991
    2739     Log7Func(("%s", INSTANCE(pThis)));
     2992    Log7Func(("%s", pThis->szInst));
    27402993
    27412994    AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN);
     
    27543007    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
    27553008             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
    2756                     Log(("%s No attached driver!\n", INSTANCE(pThis)));
     3009                    Log(("%s No attached driver!\n", pThis->szInst));
    27573010
    27583011    LEAVE_CRITICAL_SECTION;
     
    27793032{
    27803033    PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase);
    2781 
     3034LogFunc(("pInterface=%p %s\n", pInterface, pszIID));
    27823035    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN,   &pThisCC->INetworkDown);
    27833036    PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig);
     
    27973050    PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);
    27983051
    2799     Log(("%s Destroying instance\n", INSTANCE(pThis)));
     3052    Log(("%s Destroying instance\n", pThis->szInst));
    28003053
    28013054    if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT)
     
    28283081    Log7Func(("PDM device instance: %d\n", iInstance));
    28293082
    2830     RTStrPrintf(pThis->szInstanceName, sizeof(pThis->szInstanceName), "VIRTIONET%d", iInstance);
     3083    RTStrPrintf(pThis->szInst, sizeof(pThis->szInst), "VNET%d", iInstance);
     3084
     3085// Temporary for less logging clutter for singled-instance debugging
     3086*pThis->szInst = '\0';
    28313087
    28323088    pThisCC->pDevIns     = pDevIns;
     
    28453101    pThisCC->INetworkConfig.pfnSetLinkState   = virtioNetR3NetworkConfig_SetLinkState;
    28463102
     3103    pThis->hEventRxDescAvail = NIL_SUPSEMEVENT;
     3104
    28473105    /*
    28483106     * Validate configuration.
     
    28723130    if (pThis->cMsLinkUpDelay > 5000 || pThis->cMsLinkUpDelay < 100)
    28733131        LogRel(("%s WARNING! Link up delay is set to %u seconds!\n",
    2874                 INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000));
    2875 
    2876     Log(("%s Link up delay is set to %u seconds\n", INSTANCE(pThis), pThis->cMsLinkUpDelay / 1000));
     3132                pThis->szInst, pThis->cMsLinkUpDelay / 1000));
     3133
     3134    Log(("%s Link up delay is set to %u seconds\n", pThis->szInst, pThis->cMsLinkUpDelay / 1000));
    28773135
    28783136    /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */
     
    28863144     */
    28873145
    2888 #if FEATURE_OFFERED(STATUS)
    2889     pThis->virtioNetConfig.uStatus = 0;
    2890 #endif
    2891 
    2892 #if FEATURE_OFFERED(MQ)
    2893     pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS;
    2894 #endif
     3146#   if FEATURE_OFFERED(STATUS)
     3147        pThis->virtioNetConfig.uStatus = 0;
     3148#   endif
     3149
     3150#   if FEATURE_OFFERED(MQ)
     3151        pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS;
     3152#   endif
    28953153
    28963154    /* Initialize the generic Virtio core: */
     
    29103168
    29113169    /*
     3170     * Create the semaphore that will be used to synchronize/throttle
     3171     * the downstream LUN's Rx waiter thread.
     3172     */
     3173    rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEventRxDescAvail);
     3174    if (RT_FAILURE(rc))
     3175        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore"));
     3176
     3177    /*
    29123178     * Initialize VirtIO core. This will result in a "status changed" callback
    29133179     * when VirtIO is ready, at which time the Rx queue and ctrl queue worker threads will be created.
    29143180     */
    2915     rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, INSTANCE(pThis),
     3181    rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst,
    29163182                          VIRTIONET_HOST_FEATURES_OFFERED,
    29173183                          &pThis->virtioNetConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioNetConfig));
     
    29233189        return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated."));
    29243190
    2925     pThis->cVirtqPairs =   pThis->fNegotiatedFeatures & VIRTIONET_F_MQ
    2926                          ? pThis->virtioNetConfig.uMaxVirtqPairs : 1;
     3191    pThis->cVirtqPairs =  (pThis->fNegotiatedFeatures & VIRTIONET_F_MQ)
     3192                         ? pThis->virtioNetConfig.uMaxVirtqPairs  : 1;
    29273193
    29283194    pThis->cVirtQueues += pThis->cVirtqPairs * 2 + 1;
     
    29363202     */
    29373203    virtioNetR3SetVirtqNames(pThis);
     3204    pThis->aQueues[CTRLQIDX].fCtlQueue = true;
    29383205
    29393206    /*
     
    29453212
    29463213    /*
    2947      * Create the semaphore that will be used to synchronize/throttle
    2948      * the downstream LUN's Rx waiter thread.
    2949      */
    2950     rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEventRxDescAvail);
    2951     if (RT_FAILURE(rc))
    2952         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore"));
    2953 
    2954     /*
    29553214     * Attach network driver instance
    29563215     */
     
    29643223    else if (   rc == VERR_PDM_NO_ATTACHED_DRIVER
    29653224             || rc == VERR_PDM_CFG_MISSING_DRIVER_NAME)
    2966                     Log(("%s No attached driver!\n", INSTANCE(pThis)));
     3225                    Log(("%s No attached driver!\n", pThis->szInst));
    29673226
    29683227    /*
     
    29823241                              virtioNetR3SaveExec, virtioNetR3LoadExec);
    29833242    AssertRCReturn(rc, rc);
    2984 
    2985 
    29863243
    29873244   /*
     
    30173274     */
    30183275    char szTmp[128];
    3019     RTStrPrintf(szTmp, sizeof(szTmp), "%s%u", pDevIns->pReg->szName, pDevIns->iInstance);
    3020     PDMDevHlpDBGFInfoRegister(pDevIns, szTmp, "virtio-net info", virtioNetR3Info);
     3276    rc = PDMDevHlpDBGFInfoRegister(pDevIns, "virtio-net", "Display virtio-net info (help, net, features, state, pointers, queues, all)", virtioNetR3Info);
     3277    if (RT_FAILURE(rc))
     3278        LogRel(("Failed to register DBGF info for device %s\n", szTmp));
    30213279    return rc;
    30223280}
Note: See TracChangeset for help on using the changeset viewer.

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