- Timestamp:
- Jun 11, 2020 6:01:00 AM (4 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
-
Network/DevVirtioNet_1_0.cpp (modified) (110 diffs)
-
Storage/DevVirtioSCSI.cpp (modified) (51 diffs)
-
VirtIO/Virtio_1_0.cpp (modified) (53 diffs)
-
VirtIO/Virtio_1_0.h (modified) (10 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
r84468 r84774 59 59 #include "VBoxDD.h" 60 60 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 funcs63 64 61 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1) 65 62 #define VIRTIONET_MAX_QPAIRS 1 … … 70 67 #define VIRTIONET_PREALLOCATE_RX_SEG_COUNT 32 71 68 72 #define VIRTQNAME(idxQueue) (pThis->a szVirtqNames[idxQueue])69 #define VIRTQNAME(idxQueue) (pThis->aQueues[idxQueue]->szName) 73 70 #define CBVIRTQNAME(idxQueue) RTStrNLen(VIRTQNAME(idxQueue), sizeof(VIRTQNAME(idxQueue))) 74 71 #define FEATURE_ENABLED(feature) RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature) 75 72 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature)) 76 73 #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) 77 77 78 78 #define SET_LINK_UP(pState) \ … … 301 301 302 302 /** 303 * device-specific queue info 304 */ 305 struct VIRTIONETWORKER; 306 struct VIRTIONETWORKERR3; 307 308 typedef 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 /** 303 322 * Worker thread context, shared state. 304 323 */ … … 306 325 { 307 326 SUPSEMEVENT hEvtProcess; /**< handle of associated sleep/wake-up semaphore */ 327 PVIRTIONETQUEUE pQueue; /**< pointer to queue */ 328 uint16_t idx; /**< Index of this worker */ 308 329 bool volatile fSleeping; /**< Flags whether worker thread is sleeping or not */ 309 330 bool volatile fNotified; /**< Flags whether worker thread notified */ 331 bool fAssigned; /**< Flags whether worker thread has been set up */ 332 uint8_t pad; 310 333 } VIRTIONETWORKER; 311 /** Pointer to a VirtIO SCSIworker. */334 /** Pointer to a virtio net worker. */ 312 335 typedef VIRTIONETWORKER *PVIRTIONETWORKER; 313 336 … … 318 341 { 319 342 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; 321 346 } VIRTIONETWORKERR3; 322 /** Pointer to a VirtIO SCSIworker. */347 /** Pointer to a virtio net worker. */ 323 348 typedef VIRTIONETWORKERR3 *PVIRTIONETWORKERR3; 324 349 … … 340 365 341 366 /** 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 */ 350 376 uint16_t cVirtqPairs; 351 377 378 /** Number of virtqueues total (which includes each queue of each pair plus one control queue */ 352 379 uint16_t cVirtQueues; 353 380 381 /** Number of worker threads (one for the control queue and one for each Tx queue) */ 354 382 uint16_t cWorkers; 355 383 356 uint64_t fNegotiatedFeatures; 357 358 SUPSEMEVENT hTxEvent; 384 /** Alighnment */ 385 uint16_t alignment; 359 386 360 387 /** Indicates transmission in progress -- only one thread is allowed. */ 361 388 uint32_t uIsTransmitting; 362 389 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 363 411 /** MAC address obtained from the configuration. */ 364 412 RTMAC macConfigured; 365 413 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; 368 449 369 450 /** True if physical cable is attached in configuration. */ 370 451 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)];426 452 427 453 /** @name Statistic … … 489 515 R3PTRTYPE(PPDMINETWORKUP) pDrv; 490 516 491 R3PTRTYPE(PPDMTHREAD) pTxThread;492 493 517 /** Link Up(/Restore) Timer. */ 494 518 TMTIMERHANDLE hLinkUpTimer; 495 496 /** Queue to send tasks to R3. - HC ptr */497 R3PTRTYPE(PPDMQUEUE) pNotifierQueueR3;498 519 499 520 /** True if in the process of quiescing I/O */ … … 541 562 typedef CTX_SUFF(PVIRTIONET) PVIRTIONETCC; 542 563 564 #ifdef IN_RING3 565 static DECLCALLBACK(int) virtioNetR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread); 566 567 DECLINLINE(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 543 596 /** 544 597 * Wakeup the RX thread. … … 551 604 552 605 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 } 557 612 } 558 613 … … 565 620 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 566 621 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; 575 624 576 625 #if defined (IN_RING3) && defined (LOG_ENABLED) … … 578 627 #endif 579 628 580 Log10Func(("%s %s has available buffers\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));581 582 629 if (IS_RX_QUEUE(idxQueue)) 583 630 { 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)) 589 644 { 590 645 /* Wake queue's worker thread up if sleeping (e.g. a Tx queue, or the control queue */ … … 593 648 if (ASMAtomicReadBool(&pWorker->fSleeping)) 594 649 { 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)); 596 651 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 597 652 AssertRC(rc); 598 653 } 654 else 655 { 656 Log10Func(("%s %s has available buffers - worker already awake\n", pThis->szInst, pQueue->szName)); 657 } 599 658 } 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)); 601 666 } 602 667 … … 608 673 static DECLCALLBACK(int) virtioNetR3WakeupWorker(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 609 674 { 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); 613 681 } 614 682 … … 616 684 DECLINLINE(void) virtioNetR3SetVirtqNames(PVIRTIONET pThis) 617 685 { 686 RTStrCopy(pThis->aQueues[CTRLQIDX].szName, VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq"); 618 687 for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++) 619 688 { 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 } 624 692 } 625 693 … … 637 705 return; 638 706 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 710 DECLINLINE(void) virtioNetPrintFeatures(VIRTIONET *pThis, PCDBGFINFOHLP pHlp) 673 711 { 674 712 static struct … … 714 752 isOffered ? "+" : "-", isNegotiated ? "x" : " ", s_aFeatures[i].pcszDesc); 715 753 } 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 720 766 RTMemFree(pszBuf); 721 767 } 768 769 #ifdef LOG_ENABLED 770 void 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 722 799 #endif /* LOG_ENABLED */ 800 801 /** 802 * @callback_method_impl{FNDBGFHANDLERDEV, virtio-net debugger info callback.} 803 */ 804 static 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 723 969 /* 724 970 * Checks whether negotiated features have required flag combinations. … … 802 1048 uint32_t offIntra = offConfig - RT_UOFFSETOF(VIRTIONET_CONFIG_T, member); \ 803 1049 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)); \ 805 1051 else \ 806 1052 { \ … … 829 1075 else 830 1076 { 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)); 832 1078 return fWrite ? VINF_SUCCESS : VINF_IOM_MMIO_UNUSED_00; 833 1079 } … … 847 1093 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 848 1094 849 LogFunc(("%s uOffset: %d, cb: %d\n", INSTANCE(pThis), uOffset, cb));1095 LogFunc(("%s uOffset: %d, cb: %d\n", pThis->szInst, uOffset, cb)); 850 1096 RT_NOREF(pThis); 851 1097 return virtioNetR3CfgAccessed(PDMDEVINS_2_DATA(pDevIns, PVIRTIONET), uOffset, pv, cb, false /*fRead*/); … … 859 1105 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 860 1106 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)); 862 1108 RT_NOREF(pThis); 863 1109 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);885 1110 } 886 1111 … … 900 1125 901 1126 RT_NOREF(pThisCC); 902 Log7Func(("%s LOAD EXEC!!\n", INSTANCE(pThis)));1127 Log7Func(("%s LOAD EXEC!!\n", pThis->szInst)); 903 1128 904 1129 AssertReturn(uPass == SSM_PASS_FINAL, VERR_SSM_UNEXPECTED_PASS); … … 914 1139 915 1140 for (int idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++) 916 pHlp->pfnSSMGetBool(pSSM, &pThis->a fQueueAttached[idxQueue]);1141 pHlp->pfnSSMGetBool(pSSM, &pThis->aQueues[idxQueue].fAttachedToVirtioCore); 917 1142 918 1143 int rc; … … 930 1155 && (uPass == 0 || !PDMDevHlpVMTeleportedAndNotFullyResumedYet(pDevIns))) 931 1156 LogRel(("%s: The mac address differs: config=%RTmac saved=%RTmac\n", 932 INSTANCE(pThis), &pThis->macConfigured, &macConfigured));1157 pThis->szInst, &pThis->macConfigured, &macConfigured)); 933 1158 #endif 934 1159 … … 973 1198 for (int idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++) 974 1199 { 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) 977 1203 { 978 Log7Func(("%s Waking %s worker.\n", INSTANCE(pThis), VIRTQNAME(idxQueue)));979 rc = PDMDevHlpSUPSemEventSignal(pDevIns, p This->aWorkers[idxWorker].hEvtProcess);1204 Log7Func(("%s Waking %s worker.\n", pThis->szInst, pQueue->szName)); 1205 rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 980 1206 AssertRCReturn(rc, rc); 981 1207 } … … 994 1220 995 1221 RT_NOREF(pThisCC); 996 Log7Func(("%s SAVE EXEC!!\n", INSTANCE(pThis)));1222 Log7Func(("%s SAVE EXEC!!\n", pThis->szInst)); 997 1223 998 1224 pHlp->pfnSSMPutU64( pSSM, pThis->fNegotiatedFeatures); … … 1002 1228 1003 1229 for (int idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++) 1004 pHlp->pfnSSMPutBool(pSSM, pThis->a fQueueAttached[idxQueue]);1230 pHlp->pfnSSMPutBool(pSSM, pThis->aQueues[idxQueue].fAttachedToVirtioCore); 1005 1231 1006 1232 /* Save config area */ … … 1053 1279 1054 1280 Log7Func(("%s Device I/O activity quiesced: %s\n", 1055 INSTANCE(pThis), virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor)));1281 pThis->szInst, virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor))); 1056 1282 1057 1283 virtioCoreR3VmStateChanged(&pThis->Virtio, pThisCC->enmQuiescingFor); … … 1086 1312 1087 1313 /* If already quiesced invoke async callback. */ 1088 if (!ASMAtomicReadBool(&pThis->fLeafWants RxBuffers))1314 if (!ASMAtomicReadBool(&pThis->fLeafWantsEmptyRxBufs)) 1089 1315 PDMDevHlpAsyncNotificationCompleted(pDevIns); 1090 1316 … … 1098 1324 { 1099 1325 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1100 Log7Func(("%s\n", INSTANCE(pThis)));1326 Log7Func(("%s\n", pThis->szInst)); 1101 1327 pThis->fResetting = true; 1102 1328 virtioNetR3QuiesceDevice(pDevIns, kvirtIoVmStateChangedReset); … … 1111 1337 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1112 1338 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 1113 Log7Func(("%s\n", INSTANCE(pThis)));1339 Log7Func(("%s\n", pThis->szInst)); 1114 1340 1115 1341 RT_NOREF2(pThis, pThisCC); … … 1125 1351 { 1126 1352 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1127 Log7Func(("%s\n", INSTANCE(pThis)));1353 Log7Func(("%s\n", pThis->szInst)); 1128 1354 RT_NOREF(pThis); 1129 1355 virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedPowerOff); … … 1136 1362 { 1137 1363 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1138 Log7Func(("%s \n", INSTANCE(pThis)));1364 Log7Func(("%s \n", pThis->szInst)); 1139 1365 RT_NOREF(pThis); 1140 1366 virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedSuspend); … … 1213 1439 void virtioNetR3SetWriteLed(PVIRTIONETR3 pThisR3, bool fOn) 1214 1440 { 1215 Log10Func(("%s\n", fOn ? "on" : "off"));1216 1441 if (fOn) 1217 1442 pThisR3->led.Asserted.s.fWriting = pThisR3->led.Actual.s.fWriting = 1; 1218 1443 else 1219 1444 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 */ 1450 DECLINLINE(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; 1220 1459 } 1221 1460 … … 1231 1470 * @thread RX 1232 1471 */ 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 } 1472 static 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 1250 1485 else 1251 1486 { 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 1494 static bool virtioNetR3RxBufsAvail(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETQUEUE *pRxQueue) 1495 { 1264 1496 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; 1266 1503 return true; 1504 } 1505 } 1267 1506 return false; 1268 }1269 /*1270 * Returns true if VirtIO core and device are in a running and operational state1271 */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;1285 1507 } 1286 1508 … … 1294 1516 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1295 1517 1296 if (virtioNetR3 AreRxBufsAvail(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; 1300 1522 } 1301 1523 if (!timeoutMs) 1302 1524 return VERR_NET_NO_BUFFER_SPACE; 1303 1525 1304 LogF lowFunc(("%s timeoutMs=%u\n", INSTANCE(pThis), timeoutMs));1305 1306 ASMAtomicXchgBool(&pThis->fLeafWants RxBuffers, true);1526 LogFunc(("%s %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : "")); 1527 1528 ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, true); 1307 1529 STAM_PROFILE_START(&pThis->StatRxOverflow, a); 1308 1530 1309 1531 do { 1310 if (virtioNetR3 AreRxBufsAvail(pDevIns, pThis))1532 if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxQueue */)) 1311 1533 { 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; 1314 1536 } 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)); 1317 1538 1318 1539 int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pThis->hEventRxDescAvail, timeoutMs); 1319 1540 1320 1541 if (rc == VERR_TIMEOUT || rc == VERR_INTERRUPTED) 1542 { 1543 LogFunc(("Waken due to %s\n", rc == VERR_TIMEOUT ? "timeout" : "interrupted")); 1321 1544 continue; 1322 1323 if (RT_FAILURE(rc)) 1545 } 1546 if (RT_FAILURE(rc)) { 1547 LogFunc(("Waken due to failure %Rrc\n", rc)); 1324 1548 RTThreadSleep(1); 1325 1549 } 1550 LogFunc(("\n\n\n********** WAKEN!!!!! ********\n\n\n")); 1326 1551 } while (virtioNetIsOperational(pThis, pDevIns)); 1327 1552 1328 1553 STAM_PROFILE_STOP(&pThis->StatRxOverflow, a); 1329 ASMAtomicXchgBool(&pThis->fLeafWants RxBuffers, 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)); 1332 1557 return VERR_INTERRUPTED; 1333 1558 } … … 1435 1660 1436 1661 LogFunc(("%s node(%RTmac %s%s), pkt(%RTmac %s)", 1437 INSTANCE(pThis), pThis->virtioNetConfig.uMacAddress.au8,1662 pThis->szInst, pThis->virtioNetConfig.uMacAddress.au8, 1438 1663 pThis->fPromiscuous ? "promiscuous" : "", 1439 1664 pThis->fAllMulticast ? " all-multicast" : "", … … 1451 1676 && !ASMBitTest(pThis->aVlanFilter, RT_BE2H_U16(uPtr[7]) & 0xFFF)) 1452 1677 { 1453 Log11Func(("\n%s not our VLAN, returning false\n", INSTANCE(pThis)));1678 Log11Func(("\n%s not our VLAN, returning false\n", pThis->szInst)); 1454 1679 return false; 1455 1680 } … … 1505 1730 VIRTIONET_PKT_HDR_T *rxPktHdr, uint16_t cSegsAllocated, 1506 1731 PRTSGBUF pVirtSegBufToGuest, PRTSGSEG paVirtSegsToGuest, 1507 uint16_t idxRxQueue)1732 PVIRTIONETQUEUE pRxQueue) 1508 1733 { 1509 1734 uint8_t fAddPktHdr = true; 1510 RTGCPHYS gcPhysPktHdrNumBuffers = 0;1735 RTGCPHYS GCPhysPktHdrNumBuffers = 0; 1511 1736 uint16_t cDescs; 1512 1737 uint64_t uOffset; … … 1515 1740 PVIRTIO_DESC_CHAIN_T pDescChain = NULL; 1516 1741 1517 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, RXQIDX(idxRxQueue), &pDescChain, true);1742 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, pRxQueue->idx, &pDescChain, true); 1518 1743 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc); 1519 1744 … … 1526 1751 /* Length of first seg of guest Rx buf should never be less than sizeof(virtio_net_pkt_hdr). 1527 1752 * 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 */ 1529 1754 1530 1755 AssertMsgReturnStmt(pDescChain->pSgPhysReturn->paSegs[0].cbSeg >= sizeof(VIRTIONET_PKT_HDR_T), … … 1549 1774 memcpy(paVirtSegsToGuest[0].pvSeg, rxPktHdr, cbHdr); 1550 1775 1551 /* Calculate & cache addr of field to update after final value is known, in gcPhys mem */1552 gcPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].gcPhys1776 /* Calculate & cache addr of field to update after final value is known, in GCPhys mem */ 1777 GCPhysPktHdrNumBuffers = pDescChain->pSgPhysReturn->paSegs[0].GCPhys 1553 1778 + RT_UOFFSETOF(VIRTIONET_PKT_HDR_T, uNumBuffers); 1554 1779 fAddPktHdr = false; … … 1576 1801 Log7Func(("Send Rx pkt to guest...\n")); 1577 1802 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 */); 1580 1805 STAM_PROFILE_STOP(&pThis->StatReceiveStore, a); 1581 1806 … … 1589 1814 if (uOffset < cb) 1590 1815 { 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)); 1592 1817 return VERR_TOO_MUCH_DATA; 1593 1818 } … … 1595 1820 /* Fix-up pkthdr (in guest phys. memory) with number buffers (descriptors) processed */ 1596 1821 1597 int rc = PDMDevHlpPCIPhysWrite(pDevIns, gcPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs));1822 int rc = PDMDevHlpPCIPhysWrite(pDevIns, GCPhysPktHdrNumBuffers, &cDescs, sizeof(cDescs)); 1598 1823 AssertMsgRCReturn(rc, 1599 1824 ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), 1600 1825 rc); 1601 1826 1602 virtioCoreQueueSync(pDevIns, &pThis->Virtio, RXQIDX(idxRxQueue));1827 virtioCoreQueueSync(pDevIns, &pThis->Virtio, pRxQueue->idx); 1603 1828 1604 1829 return VINF_SUCCESS; … … 1622 1847 */ 1623 1848 static 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) 1625 1850 { 1626 1851 RT_NOREF(pThisCC); 1627 1852 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")); 1629 1854 VIRTIONET_PKT_HDR_T rxPktHdr = { 0 }; 1630 1855 … … 1632 1857 { 1633 1858 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, 1635 1860 pGso->cbHdrsSeg, pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 1636 1861 … … 1673 1898 1674 1899 int rc = virtioNetR3CopyRxPktToGuest(pDevIns, pThis, pvBuf, cb, &rxPktHdr, cSegsAllocated, 1675 pVirtSegBufToGuest, paVirtSegsToGuest, idxRxQueue);1900 pVirtSegBufToGuest, paVirtSegsToGuest, pRxQueue); 1676 1901 1677 1902 RTMemFree(paVirtSegsToGuest); … … 1691 1916 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1692 1917 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1693 1918 LogFunc(("\n")); 1694 1919 if (!pThis->fVirtioReady) 1695 1920 { … … 1725 1950 if (!uFeatures) 1726 1951 { 1727 Log 2Func(("%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)); 1728 1953 return VERR_NOT_SUPPORTED; 1729 1954 } 1730 1955 } 1731 1956 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)); 1733 1958 1734 1959 /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue … … 1737 1962 for (int idxQueuePair = 0; idxQueuePair < pThis->cVirtqPairs; idxQueuePair++) 1738 1963 { 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))) 1740 1967 { 1741 1968 /* Drop packets if VM is not running or cable is disconnected. */ … … 1749 1976 if (virtioNetR3AddressFilter(pThis, pvBuf, cb)) 1750 1977 { 1751 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, RXQIDX(idxQueuePair));1978 rc = virtioNetR3HandleRxPacket(pDevIns, pThis, pThisCC, pvBuf, cb, pGso, pRxQueue); 1752 1979 STAM_REL_COUNTER_ADD(&pThis->StatReceiveBytes, cb); 1753 1980 } … … 1784 2011 } 1785 2012 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)); 1787 2014 RT_NOREF(pThis); 1788 2015 } … … 1792 2019 { 1793 2020 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)); 1797 2024 RT_NOREF(pThis); 1798 2025 switch(pCtrlPktHdr->uCmd) … … 1866 2093 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1867 2094 { 1868 LogFunc(("%s Processing CTRL MAC command\n", INSTANCE(pThis)));2095 LogFunc(("%s Processing CTRL MAC command\n", pThis->szInst)); 1869 2096 1870 2097 RT_NOREF(pThisCC); … … 1898 2125 virtioNetR3PullChain(pDevIns, pThis, pDescChain, &cMacs, sizeof(cMacs)); 1899 2126 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)); 1901 2128 if (cMacs) 1902 2129 { … … 1912 2139 virtioNetR3PullChain(pDevIns, pThis, pDescChain, &cMacs, sizeof(cMacs)); 1913 2140 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)); 1915 2142 if (cMacs) 1916 2143 { … … 1923 2150 1924 2151 #ifdef LOG_ENABLED 1925 LogFunc(("%s unicast MACs:\n", INSTANCE(pThis)));2152 LogFunc(("%s unicast MACs:\n", pThis->szInst)); 1926 2153 for(unsigned i = 0; i < cMacs; i++) 1927 2154 LogFunc((" %RTmac\n", &pThis->aMacUnicastFilter[i])); 1928 2155 1929 LogFunc(("%s multicast MACs:\n", INSTANCE(pThis)));2156 LogFunc(("%s multicast MACs:\n", pThis->szInst)); 1930 2157 for(unsigned i = 0; i < cMacs; i++) 1931 2158 LogFunc((" %RTmac\n", &pThis->aMacMulticastFilter[i])); … … 1939 2166 PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTIO_DESC_CHAIN_T pDescChain) 1940 2167 { 1941 LogFunc(("%s Processing CTRL VLAN command\n", INSTANCE(pThis)));2168 LogFunc(("%s Processing CTRL VLAN command\n", pThis->szInst)); 1942 2169 1943 2170 RT_NOREF(pThisCC); … … 1949 2176 virtioNetR3PullChain(pDevIns, pThis, pDescChain, &uVlanId, sizeof(uVlanId)); 1950 2177 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)); 1953 2180 switch (pCtrlPktHdr->uCmd) 1954 2181 { … … 1968 2195 PVIRTIO_DESC_CHAIN_T pDescChain) 1969 2196 { 1970 LogFunc(("%s Received CTRL packet from guest\n", INSTANCE(pThis)));2197 LogFunc(("%s Received CTRL packet from guest\n", pThis->szInst)); 1971 2198 1972 2199 if (pDescChain->cbPhysSend < 2) 1973 2200 { 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)); 1975 2202 return; 1976 2203 } 1977 2204 else if (pDescChain->cbPhysReturn < sizeof(VIRTIONET_CTRL_HDR_T_ACK)) 1978 2205 { 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)); 1980 2207 return; 1981 2208 } … … 1994 2221 RT_MIN(pDescChain->cbPhysSend, sizeof(VIRTIONET_CTRL_HDR_T))); 1995 2222 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)); 1997 2224 1998 2225 uint8_t uAck; … … 2013 2240 { 2014 2241 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)); 2016 2243 break; 2017 2244 } 2018 2245 if (pCtrlPktHdr->uCmd != VIRTIONET_CTRL_ANNOUNCE_ACK) 2019 2246 { 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)); 2021 2248 break; 2022 2249 } 2023 2250 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)); 2025 2252 break; 2026 2253 … … 2055 2282 RTSgBufInit(pReturnSegBuf, paReturnSegs, cSegs); 2056 2283 2057 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pReturnSegBuf, pDescChain, true );2284 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, CTRLQIDX, pReturnSegBuf, pDescChain, true /* fFence */); 2058 2285 virtioCoreQueueSync(pDevIns, &pThis->Virtio, CTRLQIDX); 2059 2286 … … 2065 2292 2066 2293 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")); 2068 2295 } 2069 2296 … … 2074 2301 return rc; 2075 2302 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", 2077 2304 pPktHdr->uFlags, pPktHdr->uGsoType, pPktHdr->uHdrLen, 2078 2305 pPktHdr->uGsoSize, pPktHdr->uChksumStart, pPktHdr->uChksumOffset, cbFrame)); … … 2128 2355 { 2129 2356 Log4Func(("%s HdrLen before adjustment %d.\n", 2130 INSTANCE(pThis), pGso->cbHdrsTotal));2357 pThis->szInst, pGso->cbHdrsTotal)); 2131 2358 switch (pGso->u8Type) 2132 2359 { … … 2146 2373 ((PPDMNETWORKGSO)pSgBuf->pvUser)->cbHdrsSeg = pGso->cbHdrsSeg; 2147 2374 Log4Func(("%s adjusted HdrLen to %d.\n", 2148 INSTANCE(pThis), pGso->cbHdrsTotal));2375 pThis->szInst, pGso->cbHdrsTotal)); 2149 2376 } 2150 2377 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, 2152 2379 pGso->cbMaxSeg, pGso->offHdr1, pGso->offHdr2)); 2153 2380 STAM_REL_COUNTER_INC(&pThis->StatTransmitGSO); … … 2163 2390 } 2164 2391 2165 return pThisCC->pDrv->pfnSendBuf(pThisCC->pDrv, pSgBuf, false);2392 return pThisCC->pDrv->pfnSendBuf(pThisCC->pDrv, pSgBuf, true /* fOnWorkerThread */); 2166 2393 } 2167 2394 2168 2395 static void virtioNetR3TransmitPendingPackets(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC, 2169 uint16_t idxTxQueue, bool fOnWorkerThread)2396 PVIRTIONETQUEUE pTxQueue, bool fOnWorkerThread) 2170 2397 { 2171 2398 … … 2183 2410 { 2184 2411 LogFunc(("%s Ignoring Tx requests. VirtIO not ready (status=0x%x).\n", 2185 INSTANCE(pThis), pThis->virtioNetConfig.uStatus));2412 pThis->szInst, pThis->virtioNetConfig.uStatus)); 2186 2413 return; 2187 2414 } … … 2189 2416 if (!pThis->fCableConnected) 2190 2417 { 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)); 2192 2419 return; 2193 2420 } … … 2205 2432 } 2206 2433 2207 int cPkts = virtioCore R3QueuePendingCount(pVirtio->pDevInsR3, pVirtio, idxTxQueue);2434 int cPkts = virtioCoreQueueAvailCount(pVirtio->pDevInsR3, pVirtio, pTxQueue->idx); 2208 2435 if (!cPkts) 2209 2436 { 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)); 2211 2438 2212 2439 if (pDrv) … … 2216 2443 return; 2217 2444 } 2218 LogFunc(("%s About to transmit %d pending packet s\n", INSTANCE(pThis), cPkts));2445 LogFunc(("%s About to transmit %d pending packet%c\n", pThis->szInst, cPkts, cPkts == 1 ? ' ' : 's')); 2219 2446 2220 2447 virtioNetR3SetWriteLed(pThisCC, true); … … 2222 2449 int rc; 2223 2450 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)); 2227 2454 2228 2455 PVIRTIOSGBUF pSgPhysSend = pDescChain->pSgPhysSend; … … 2239 2466 uSize += paSegsFromGuest[i].cbSeg; 2240 2467 2241 Log5Func(("%s complete frame is %u bytes.\n", INSTANCE(pThis), uSize));2468 Log5Func(("%s complete frame is %u bytes.\n", pThis->szInst, uSize)); 2242 2469 Assert(uSize <= VIRTIONET_MAX_FRAME_SIZE); 2243 2470 … … 2248 2475 if (pThisCC->pDrv) 2249 2476 { 2250 PDMNETWORKGSO Gso;2251 PPDMNETWORKGSO pGso = virtioNetR3SetupGsoCtx(&Gso, &PktHdr);2252 2477 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); 2253 2486 2254 2487 PPDMSCATTERGATHER pSgBufToPdmLeafDevice; … … 2258 2491 STAM_REL_COUNTER_INC(&pThis->StatTransmitPackets); 2259 2492 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));2266 2493 2267 2494 size_t cbCopied = 0; … … 2272 2499 { 2273 2500 PVIRTIOSGSEG paSeg = &pSgPhysSend->paSegs[pSgPhysSend->idxSeg]; 2274 uint64_t srcSgStart = (uint64_t)paSeg-> gcPhys;2501 uint64_t srcSgStart = (uint64_t)paSeg->GCPhys; 2275 2502 uint64_t srcSgLen = (uint64_t)paSeg->cbSeg; 2276 uint64_t srcSgCur = (uint64_t)pSgPhysSend-> gcPhysCur;2503 uint64_t srcSgCur = (uint64_t)pSgPhysSend->GCPhysCur; 2277 2504 cbCopied = RT_MIN((uint64_t)cbRemain, srcSgLen - (srcSgCur - srcSgStart)); 2278 2505 PDMDevHlpPCIPhysRead(pDevIns, 2279 (RTGCPHYS)pSgPhysSend-> gcPhysCur,2506 (RTGCPHYS)pSgPhysSend->GCPhysCur, 2280 2507 ((uint8_t *)pSgBufToPdmLeafDevice->aSegs[0].pvSeg) + uOffset, cbCopied); 2281 2508 virtioCoreSgBufAdvance(pSgPhysSend, cbCopied); … … 2291 2518 if (RT_FAILURE(rc)) 2292 2519 { 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)); 2294 2521 STAM_PROFILE_STOP(&pThis->StatTransmitSend, a); 2295 2522 STAM_PROFILE_ADV_STOP(&pThis->StatTransmit, a); … … 2308 2535 2309 2536 /* Remove this descriptor chain from the available ring */ 2310 virtioCoreR3QueueSkip(pVirtio, idxTxQueue);2537 virtioCoreR3QueueSkip(pVirtio, pTxQueue->idx); 2311 2538 2312 2539 /* 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 */); 2314 2541 2315 2542 /* 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); 2317 2544 } 2318 2545 … … 2337 2564 PPDMDEVINS pDevIns = pThisCC->pDevIns; 2338 2565 PVIRTIONET pThis = PDMDEVINS_2_DATA(pThisCC->pDevIns, PVIRTIONET); 2339 2566 PVIRTIONETQUEUE pTxQueue = &pThis->aQueues[TXQIDX(0)]; 2340 2567 STAM_COUNTER_INC(&pThis->StatTransmitByNetwork); 2341 2568 2342 2569 /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue 2343 2570 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 2427 2574 2428 2575 #ifdef USING_CRITICAL_SECTION … … 2431 2578 RT_NOREF(pDevIns, pThis, rcBusy); 2432 2579 /* 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)); 2434 2581 return VINF_SUCCESS; 2435 2582 } … … 2438 2585 { 2439 2586 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)); 2441 2588 } 2442 2589 #endif /* USING_CRITICAL_SECTION */ … … 2459 2606 LEAVE_CRITICAL_SECTION; 2460 2607 2461 LogFunc(("%s Link is up\n", INSTANCE(pThis)));2608 LogFunc(("%s Link is up\n", pThis->szInst)); 2462 2609 2463 2610 if (pThisCC->pDrv) … … 2488 2635 AssertRC(rc); 2489 2636 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 } 2503 2639 } 2504 2640 … … 2517 2653 if (LogIs7Enabled()) 2518 2654 { 2519 LogFunc(("%s", INSTANCE(pThis)));2655 LogFunc(("%s", pThis->szInst)); 2520 2656 switch(enmState) 2521 2657 { … … 2551 2687 if (fCachedLinkIsUp) 2552 2688 { 2553 Log(("%s Link is up\n", INSTANCE(pThis)));2689 Log(("%s Link is up\n", pThis->szInst)); 2554 2690 pThis->fCableConnected = true; 2555 2691 SET_LINK_UP(pThis); … … 2560 2696 /* The link was brought down explicitly, make sure it won't come up by timer. */ 2561 2697 PDMDevHlpTimerStop(pDevIns, pThisCC->hLinkUpTimer); 2562 Log(("%s Link is down\n", INSTANCE(pThis)));2698 Log(("%s Link is down\n", pThis->szInst)); 2563 2699 pThis->fCableConnected = false; 2564 2700 SET_LINK_DOWN(pThis); … … 2570 2706 return VINF_SUCCESS; 2571 2707 } 2708 /** 2709 * @interface_method_impl{PDMINETWORKCONFIG,pfnGetLinkState} 2710 */ 2711 static 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 } 2572 2718 2573 2719 static int virtioNetR3DestroyWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2574 2720 { 2575 Log10Func(("%s\n", INSTANCE(pThis)));2721 Log10Func(("%s\n", pThis->szInst)); 2576 2722 int rc = VINF_SUCCESS; 2577 2723 for (unsigned idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++) 2578 2724 { 2579 PVIRTIONETWORKER pWorker = &pThis->aWorkers[idxWorker]; 2725 PVIRTIONETWORKER pWorker = &pThis->aWorkers[idxWorker]; 2726 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxWorker]; 2727 2580 2728 if (pWorker->hEvtProcess != NIL_SUPSEMEVENT) 2581 2729 { … … 2583 2731 pWorker->hEvtProcess = NIL_SUPSEMEVENT; 2584 2732 } 2585 if (p ThisCC->aWorkers[idxWorker].pThread)2733 if (pWorkerR3->pThread) 2586 2734 { 2587 2735 int rcThread; 2588 rc = PDMDevHlpThreadDestroy(pDevIns, p ThisCC->aWorkers[idxWorker].pThread, &rcThread);2736 rc = PDMDevHlpThreadDestroy(pDevIns, pWorkerR3->pThread, &rcThread); 2589 2737 if (RT_FAILURE(rc) || RT_FAILURE(rcThread)) 2590 2738 AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", __FUNCTION__, rc, rcThread)); 2591 pThisCC->aWorkers[idxWorker].pThread = NULL;2739 pWorkerR3->pThread = NULL; 2592 2740 } 2593 2741 } … … 2595 2743 } 2596 2744 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); 2745 static 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); 2603 2752 2604 2753 if (RT_FAILURE(rc)) … … 2606 2755 N_("DevVirtioNET: Failed to create SUP event semaphore")); 2607 2756 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 2619 2774 return rc; 2620 2775 } … … 2622 2777 static int virtioNetR3CreateWorkerThreads(PPDMDEVINS pDevIns, PVIRTIONET pThis, PVIRTIONETCC pThisCC) 2623 2778 { 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); 2631 2799 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; 2636 2805 return rc; 2637 2806 } 2807 2808 /** 2809 * @callback_method_impl{FNPDMTHREADDEV} 2810 */ 2811 static 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 2638 2885 /** 2639 2886 * @callback_method_impl{VIRTIOCORER3,pfnStatusChanged} … … 2649 2896 { 2650 2897 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 2652 2907 pThis->virtioNetConfig.uStatus = pThis->fCableConnected ? VIRTIONET_F_LINK_UP : 0; 2653 2908 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 2661 2912 for (unsigned idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++) 2662 2913 { 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 */); 2667 2920 } 2668 2921 } 2669 2922 else 2670 2923 { 2671 LogFunc(("%s VirtIO is resetting\n", INSTANCE(pThis)));2924 LogFunc(("%s VirtIO is resetting\n", pThis->szInst)); 2672 2925 2673 2926 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")); 2675 2928 2676 2929 pThis->fPromiscuous = true; … … 2690 2943 pThisCC->pDrv->pfnSetPromiscuousMode(pThisCC->pDrv, true); 2691 2944 2692 for (u nsignedidxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++)2693 pThis->a fQueueAttached[idxQueue]= false;2945 for (uint16_t idxQueue = 0; idxQueue < pThis->cVirtQueues; idxQueue++) 2946 pThis->aQueues[idxQueue].fAttachedToVirtioCore = false; 2694 2947 } 2695 2948 } … … 2709 2962 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2710 2963 2711 Log7Func(("%s\n", INSTANCE(pThis)));2964 Log7Func(("%s\n", pThis->szInst)); 2712 2965 AssertLogRelReturnVoid(iLUN == 0); 2713 2966 … … 2737 2990 RT_NOREF(fFlags); 2738 2991 2739 Log7Func(("%s", INSTANCE(pThis)));2992 Log7Func(("%s", pThis->szInst)); 2740 2993 2741 2994 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN); … … 2754 3007 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER 2755 3008 || 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)); 2757 3010 2758 3011 LEAVE_CRITICAL_SECTION; … … 2779 3032 { 2780 3033 PVIRTIONETR3 pThisCC = RT_FROM_MEMBER(pInterface, VIRTIONETCC, IBase); 2781 3034 LogFunc(("pInterface=%p %s\n", pInterface, pszIID)); 2782 3035 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKDOWN, &pThisCC->INetworkDown); 2783 3036 PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThisCC->INetworkConfig); … … 2797 3050 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC); 2798 3051 2799 Log(("%s Destroying instance\n", INSTANCE(pThis)));3052 Log(("%s Destroying instance\n", pThis->szInst)); 2800 3053 2801 3054 if (pThis->hEventRxDescAvail != NIL_SUPSEMEVENT) … … 2828 3081 Log7Func(("PDM device instance: %d\n", iInstance)); 2829 3082 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'; 2831 3087 2832 3088 pThisCC->pDevIns = pDevIns; … … 2845 3101 pThisCC->INetworkConfig.pfnSetLinkState = virtioNetR3NetworkConfig_SetLinkState; 2846 3102 3103 pThis->hEventRxDescAvail = NIL_SUPSEMEVENT; 3104 2847 3105 /* 2848 3106 * Validate configuration. … … 2872 3130 if (pThis->cMsLinkUpDelay > 5000 || pThis->cMsLinkUpDelay < 100) 2873 3131 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)); 2877 3135 2878 3136 /* Copy the MAC address configured for the VM to the MMIO accessible Virtio dev-specific config area */ … … 2886 3144 */ 2887 3145 2888 # if FEATURE_OFFERED(STATUS)2889 pThis->virtioNetConfig.uStatus = 0;2890 # endif2891 2892 # if FEATURE_OFFERED(MQ)2893 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS;2894 # endif3146 # 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 2895 3153 2896 3154 /* Initialize the generic Virtio core: */ … … 2910 3168 2911 3169 /* 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 /* 2912 3178 * Initialize VirtIO core. This will result in a "status changed" callback 2913 3179 * when VirtIO is ready, at which time the Rx queue and ctrl queue worker threads will be created. 2914 3180 */ 2915 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, INSTANCE(pThis),3181 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst, 2916 3182 VIRTIONET_HOST_FEATURES_OFFERED, 2917 3183 &pThis->virtioNetConfig /*pvDevSpecificCap*/, sizeof(pThis->virtioNetConfig)); … … 2923 3189 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated.")); 2924 3190 2925 pThis->cVirtqPairs = pThis->fNegotiatedFeatures & VIRTIONET_F_MQ2926 ? pThis->virtioNetConfig.uMaxVirtqPairs :1;3191 pThis->cVirtqPairs = (pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) 3192 ? pThis->virtioNetConfig.uMaxVirtqPairs : 1; 2927 3193 2928 3194 pThis->cVirtQueues += pThis->cVirtqPairs * 2 + 1; … … 2936 3202 */ 2937 3203 virtioNetR3SetVirtqNames(pThis); 3204 pThis->aQueues[CTRLQIDX].fCtlQueue = true; 2938 3205 2939 3206 /* … … 2945 3212 2946 3213 /* 2947 * Create the semaphore that will be used to synchronize/throttle2948 * 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 /*2955 3214 * Attach network driver instance 2956 3215 */ … … 2964 3223 else if ( rc == VERR_PDM_NO_ATTACHED_DRIVER 2965 3224 || 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)); 2967 3226 2968 3227 /* … … 2982 3241 virtioNetR3SaveExec, virtioNetR3LoadExec); 2983 3242 AssertRCReturn(rc, rc); 2984 2985 2986 3243 2987 3244 /* … … 3017 3274 */ 3018 3275 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)); 3021 3279 return rc; 3022 3280 } -
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r84504 r84774 112 112 #define VIRTQ_REQ_BASE 2 /**< Spec-defined base index of request queues */ 113 113 114 #define VIRTQNAME( qIdx) (pThis->aszVirtqNames[qIdx]) /**< Macro to get queue name from its index */115 #define CBVIRTQNAME( qIdx) RTStrNLen(VIRTQNAME(qIdx), sizeof(VIRTQNAME(qIdx)))116 117 #define IS_REQ_QUEUE( qIdx) (qIdx >= VIRTQ_REQ_BASE && qIdx< VIRTIOSCSI_QUEUE_CNT)114 #define VIRTQNAME(idxQueue) (pThis->aszVirtqNames[idxQueue]) /**< Macro to get queue name from its index */ 115 #define CBVIRTQNAME(idxQueue) RTStrNLen(VIRTQNAME(idxQueue), sizeof(VIRTQNAME(idxQueue))) 116 117 #define IS_REQ_QUEUE(idxQueue) (idxQueue >= VIRTQ_REQ_BASE && idxQueue < VIRTIOSCSI_QUEUE_CNT) 118 118 119 119 #define VIRTIO_IS_IN_DIRECTION(pMediaExTxDirEnumValue) \ … … 123 123 ((pMediaExTxDirEnumValue) == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE) 124 124 125 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, idxQueue) \ 126 (virtioCoreQueueAvailCount(pDevIns, pVirtio, idxQueue) == 0) 125 127 126 128 /********************************************************************************************************************************* … … 355 357 { 356 358 R3PTRTYPE(PPDMTHREAD) pThread; /**< pointer to worker thread's handle */ 357 uint16_t auRedoDescs[VIRTQ_MAX_ SIZE];/**< List of previously suspended reqs to re-submit */359 uint16_t auRedoDescs[VIRTQ_MAX_ENTRIES];/**< List of previously suspended reqs to re-submit */ 358 360 uint16_t cRedoDescs; /**< Number of redo desc chain head desc idxes in list */ 359 361 } VIRTIOSCSIWORKERR3; … … 554 556 PDMMEDIAEXIOREQ hIoReq; /**< Handle of I/O request */ 555 557 PVIRTIOSCSITARGET pTarget; /**< Target */ 556 uint16_t qIdx; /**< Index of queue this request arrived on */558 uint16_t idxQueue; /**< Index of queue this request arrived on */ 557 559 PVIRTIO_DESC_CHAIN_T pDescChain; /**< Prepared desc chain pulled from virtq avail ring */ 558 560 size_t cbDataIn; /**< size of dataout buffer */ … … 573 575 * @todo this causes burn if I prefix with at-sign. This callback is in VIRTIOCORER0 and VIRTIOCORER3 574 576 */ 575 static DECLCALLBACK(void) virtioScsiNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t qIdx)577 static DECLCALLBACK(void) virtioScsiNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 576 578 { 577 579 … … 579 581 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 580 582 581 AssertReturnVoid( qIdx< VIRTIOSCSI_QUEUE_CNT);582 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[ qIdx];583 AssertReturnVoid(idxQueue < VIRTIOSCSI_QUEUE_CNT); 584 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[idxQueue]; 583 585 584 586 #if defined (IN_RING3) && defined (LOG_ENABLED) … … 586 588 #endif 587 589 588 if ( qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx))589 { 590 Log6Func(("%s has available data\n", VIRTQNAME( qIdx)));590 if (idxQueue == CONTROLQ_IDX || IS_REQ_QUEUE(idxQueue)) 591 { 592 Log6Func(("%s has available data\n", VIRTQNAME(idxQueue))); 591 593 /* Wake queue's worker thread up if sleeping */ 592 594 if (!ASMAtomicXchgBool(&pWorker->fNotified, true)) … … 594 596 if (ASMAtomicReadBool(&pWorker->fSleeping)) 595 597 { 596 Log6Func(("waking %s worker.\n", VIRTQNAME( qIdx)));598 Log6Func(("waking %s worker.\n", VIRTQNAME(idxQueue))); 597 599 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pWorker->hEvtProcess); 598 600 AssertRC(rc); … … 600 602 } 601 603 } 602 else if ( qIdx== EVENTQ_IDX)603 { 604 Log3Func(("Driver queued buffer(s) to %s\n", VIRTQNAME( qIdx)));604 else if (idxQueue == EVENTQ_IDX) 605 { 606 Log3Func(("Driver queued buffer(s) to %s\n", VIRTQNAME(idxQueue))); 605 607 // if (ASMAtomicXchgBool(&pThis->fEventsMissed, false)) 606 608 // virtioScsiR3ReportEventsMissed(pDevIns, pThis, 0); 607 609 } 608 610 else 609 LogFunc(("Unexpected queue idx (ignoring): %d\n", qIdx));611 LogFunc(("Unexpected queue idx (ignoring): %d\n", idxQueue)); 610 612 } 611 613 … … 618 620 RTStrCopy(pThis->aszVirtqNames[CONTROLQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "controlq"); 619 621 RTStrCopy(pThis->aszVirtqNames[EVENTQ_IDX], VIRTIO_MAX_QUEUE_NAME_SIZE, "eventq"); 620 for (uint16_t qIdx = VIRTQ_REQ_BASE; qIdx < VIRTQ_REQ_BASE + VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++)621 RTStrPrintf(pThis->aszVirtqNames[ qIdx], VIRTIO_MAX_QUEUE_NAME_SIZE,622 "requestq<%d>", qIdx- VIRTQ_REQ_BASE);622 for (uint16_t idxQueue = VIRTQ_REQ_BASE; idxQueue < VIRTQ_REQ_BASE + VIRTIOSCSI_REQ_QUEUE_CNT; idxQueue++) 623 RTStrPrintf(pThis->aszVirtqNames[idxQueue], VIRTIO_MAX_QUEUE_NAME_SIZE, 624 "requestq<%d>", idxQueue - VIRTQ_REQ_BASE); 623 625 } 624 626 … … 808 810 * @param pThis VirtIO SCSI shared instance data. 809 811 * @param pThisCC VirtIO SCSI ring-3 instance data. 810 * @param qIdxQueue index812 * @param idxQueue Queue index 811 813 * @param pDescChain Pointer to pre-processed descriptor chain pulled from virtq 812 814 * @param pRespHdr Response header … … 816 818 * @returns VINF_SUCCESS 817 819 */ 818 static int virtioScsiR3ReqErr(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, uint16_t qIdx,820 static int virtioScsiR3ReqErr(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, uint16_t idxQueue, 819 821 PVIRTIO_DESC_CHAIN_T pDescChain, REQ_RESP_HDR_T *pRespHdr, uint8_t *pbSense, 820 822 size_t cbSenseCfg) … … 850 852 pRespHdr->uResponse = VIRTIOSCSI_S_RESET; 851 853 852 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, &ReqSgBuf, pDescChain, true /* fFence */);853 virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx);854 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, idxQueue, &ReqSgBuf, pDescChain, true /* fFence */); 855 virtioCoreQueueSync(pDevIns, &pThis->Virtio, idxQueue); 854 856 855 857 if (!ASMAtomicDecU32(&pThis->cActiveReqs) && pThisCC->fQuiescing) … … 869 871 * @param pThis VirtIO SCSI shared instance data. 870 872 * @param pThisCC VirtIO SCSI ring-3 instance data. 871 * @param qIdxQueue index873 * @param idxQueue Queue index 872 874 * @param pDescChain Pointer to pre-processed descriptor chain pulled from virtq 873 875 * @param cbResidual The number of residual bytes or something like that. … … 880 882 * @returns VINF_SUCCESS 881 883 */ 882 static int virtioScsiR3ReqErr4(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, uint16_t qIdx,884 static int virtioScsiR3ReqErr4(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, uint16_t idxQueue, 883 885 PVIRTIO_DESC_CHAIN_T pDescChain, size_t cbResidual, uint8_t bStatus, uint8_t bResponse, 884 886 uint8_t *pbSense, size_t cbSense, size_t cbSenseCfg) … … 891 893 RespHdr.uResponse = bResponse; 892 894 893 return virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &RespHdr, pbSense, cbSenseCfg);895 return virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, idxQueue, pDescChain, &RespHdr, pbSense, cbSenseCfg); 894 896 } 895 897 … … 1013 1015 respHdr.uResidual = pReq->cbDataIn & UINT32_MAX; 1014 1016 1015 virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, pReq-> qIdx, pReq->pDescChain, &respHdr, abSense,1017 virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, pReq->idxQueue, pReq->pDescChain, &respHdr, abSense, 1016 1018 RT_MIN(pThis->virtioScsiConfig.uSenseSize, VIRTIOSCSI_SENSE_SIZE_MAX)); 1017 1019 } … … 1039 1041 VERR_BUFFER_OVERFLOW); 1040 1042 1041 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, pReq-> qIdx, &ReqSgBuf, pReq->pDescChain, true /* fFence TBD */);1042 virtioCoreQueueSync(pDevIns, &pThis->Virtio, pReq-> qIdx);1043 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, pReq->idxQueue, &ReqSgBuf, pReq->pDescChain, true /* fFence TBD */); 1044 virtioCoreQueueSync(pDevIns, &pThis->Virtio, pReq->idxQueue); 1043 1045 1044 1046 Log2(("-----------------------------------------------------------------------------------------\n")); … … 1085 1087 cbCopied = RT_MIN(pSgBuf->cbSegLeft, pSgPhysReturn->cbSegLeft); 1086 1088 Assert(cbCopied > 0); 1087 PDMDevHlpPCIPhysWriteUser(pDevIns, pSgPhysReturn-> gcPhysCur, pSgBuf->pvSegCur, cbCopied);1089 PDMDevHlpPCIPhysWriteUser(pDevIns, pSgPhysReturn->GCPhysCur, pSgBuf->pvSegCur, cbCopied); 1088 1090 RTSgBufAdvance(pSgBuf, cbCopied); 1089 1091 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopied); … … 1123 1125 cbCopied = RT_MIN(pSgBuf->cbSegLeft, pSgPhysSend->cbSegLeft); 1124 1126 Assert(cbCopied > 0); 1125 PDMDevHlpPCIPhysReadUser(pDevIns, pSgPhysSend-> gcPhysCur, pSgBuf->pvSegCur, cbCopied);1127 PDMDevHlpPCIPhysReadUser(pDevIns, pSgPhysSend->GCPhysCur, pSgBuf->pvSegCur, cbCopied); 1126 1128 RTSgBufAdvance(pSgBuf, cbCopied); 1127 1129 virtioCoreSgBufAdvance(pSgPhysSend, cbCopied); … … 1141 1143 */ 1142 1144 static int virtioScsiR3ReqSubmit(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, 1143 uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)1145 uint16_t idxQueue, PVIRTIO_DESC_CHAIN_T pDescChain) 1144 1146 { 1145 1147 … … 1229 1231 { 1230 1232 Log2Func(("Error submitting request, bad LUN format\n")); 1231 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, qIdx, pDescChain, cbDataIn + cbDataOut, 0 /*bStatus*/,1233 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, idxQueue, pDescChain, cbDataIn + cbDataOut, 0 /*bStatus*/, 1232 1234 VIRTIOSCSI_S_FAILURE, NULL /*pbSense*/, 0 /*cbSense*/, cbSenseCfg); 1233 1235 } … … 1244 1246 0, SCSI_SENSE_ILLEGAL_REQUEST, 1245 1247 0, 0, 0, 0, 10, SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 0, 0 }; 1246 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, qIdx, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION,1248 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, idxQueue, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION, 1247 1249 VIRTIOSCSI_S_BAD_TARGET, abSense, sizeof(abSense), cbSenseCfg); 1248 1250 } … … 1255 1257 0, SCSI_SENSE_ILLEGAL_REQUEST, 1256 1258 0, 0, 0, 0, 10, SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED, 0, 0 }; 1257 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, qIdx, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION,1259 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, idxQueue, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION, 1258 1260 VIRTIOSCSI_S_OK, abSense, sizeof(abSense), cbSenseCfg); 1259 1261 } … … 1263 1265 { 1264 1266 Log2Func(("Aborting req submission because reset is in progress\n")); 1265 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, qIdx, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_OK,1267 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, idxQueue, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_OK, 1266 1268 VIRTIOSCSI_S_RESET, NULL /*pbSense*/, 0 /*cbSense*/, cbSenseCfg); 1267 1269 } … … 1274 1276 uint8_t abSense[] = { RT_BIT(7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED, 1275 1277 0, SCSI_SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 10, 0, 0, 0 }; 1276 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, qIdx, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION,1278 return virtioScsiR3ReqErr4(pDevIns, pThis, pThisCC, idxQueue, pDescChain, cbDataIn + cbDataOut, SCSI_STATUS_CHECK_CONDITION, 1277 1279 VIRTIOSCSI_S_FAILURE, abSense, sizeof(abSense), cbSenseCfg); 1278 1280 } … … 1292 1294 pReq->hIoReq = hIoReq; 1293 1295 pReq->pTarget = pTarget; 1294 pReq-> qIdx = qIdx;1296 pReq->idxQueue = idxQueue; 1295 1297 pReq->cbDataIn = cbDataIn; 1296 1298 pReq->cbDataOut = cbDataOut; … … 1339 1341 respHdr.uResponse = VIRTIOSCSI_S_FAILURE; 1340 1342 respHdr.uResidual = (cbDataIn + cbDataOut) & UINT32_MAX; 1341 virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, qIdx, pDescChain, &respHdr, abSense, cbSenseCfg);1343 virtioScsiR3ReqErr(pDevIns, pThis, pThisCC, idxQueue, pDescChain, &respHdr, abSense, cbSenseCfg); 1342 1344 virtioScsiR3FreeReq(pTarget, pReq); 1343 1345 } … … 1353 1355 * @param pThis VirtIO SCSI shared instance data. 1354 1356 * @param pThisCC VirtIO SCSI ring-3 instance data. 1355 * @param qIdxCONTROLQ_IDX1357 * @param idxQueue CONTROLQ_IDX 1356 1358 * @param pDescChain Descriptor chain to process. 1357 1359 */ 1358 1360 static int virtioScsiR3Ctrl(PPDMDEVINS pDevIns, PVIRTIOSCSI pThis, PVIRTIOSCSICC pThisCC, 1359 uint16_t qIdx, PVIRTIO_DESC_CHAIN_T pDescChain)1361 uint16_t idxQueue, PVIRTIO_DESC_CHAIN_T pDescChain) 1360 1362 { 1361 1363 AssertReturn(pDescChain->cbPhysSend >= RT_MIN(sizeof(VIRTIOSCSI_CTRL_AN_T), … … 1398 1400 uint32_t uScsiLun = RT_MAKE_U16(ScsiCtrlUnion.Tmf.abScsiLun[3], ScsiCtrlUnion.Tmf.abScsiLun[2]) & 0x3fff; 1399 1401 Log2Func(("[%s] (Target: %d LUN: %d) Task Mgt Function: %s\n", 1400 VIRTQNAME( qIdx), uTarget, uScsiLun, virtioGetTMFTypeText(ScsiCtrlUnion.Tmf.uSubtype)));1402 VIRTQNAME(idxQueue), uTarget, uScsiLun, virtioGetTMFTypeText(ScsiCtrlUnion.Tmf.uSubtype))); 1401 1403 1402 1404 if (uTarget >= pThis->cTargets || !pThisCC->paTargetInstances[uTarget].fPresent) … … 1459 1461 virtioGetControlAsyncMaskText(szTypeText, sizeof(szTypeText), ScsiCtrlUnion.AsyncNotify.fEventsRequested); 1460 1462 Log2Func(("[%s] (Target: %d LUN: %d) Async. Notification Query: %s\n", 1461 VIRTQNAME( qIdx), uTarget, uScsiLun, szTypeText));1463 VIRTQNAME(idxQueue), uTarget, uScsiLun, szTypeText)); 1462 1464 } 1463 1465 #endif … … 1484 1486 virtioGetControlAsyncMaskText(szTypeText, sizeof(szTypeText), ScsiCtrlUnion.AsyncNotify.fEventsRequested); 1485 1487 Log2Func(("[%s] (Target: %d LUN: %d) Async. Notification Subscribe: %s\n", 1486 VIRTQNAME( qIdx), uTarget, uScsiLun, szTypeText));1488 VIRTQNAME(idxQueue), uTarget, uScsiLun, szTypeText)); 1487 1489 } 1488 1490 #endif … … 1505 1507 default: 1506 1508 { 1507 LogFunc(("Unknown control type extracted from %s: %u\n", VIRTQNAME( qIdx), ScsiCtrlUnion.Type.uType));1509 LogFunc(("Unknown control type extracted from %s: %u\n", VIRTQNAME(idxQueue), ScsiCtrlUnion.Type.uType)); 1508 1510 1509 1511 bResponse = VIRTIOSCSI_S_FAILURE; … … 1524 1526 RTSgBufInit(&ReqSgBuf, aReqSegs, cSegs); 1525 1527 1526 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, qIdx, &ReqSgBuf, pDescChain, true /*fFence*/);1527 virtioCoreQueueSync(pDevIns, &pThis->Virtio, qIdx);1528 virtioCoreR3QueuePut(pDevIns, &pThis->Virtio, idxQueue, &ReqSgBuf, pDescChain, true /*fFence*/); 1529 virtioCoreQueueSync(pDevIns, &pThis->Virtio, idxQueue); 1528 1530 1529 1531 return VINF_SUCCESS; … … 1544 1546 static DECLCALLBACK(int) virtioScsiR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread) 1545 1547 { 1546 uint16_t const qIdx= (uint16_t)(uintptr_t)pThread->pvUser;1548 uint16_t const idxQueue = (uint16_t)(uintptr_t)pThread->pvUser; 1547 1549 PVIRTIOSCSI pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIOSCSI); 1548 1550 PVIRTIOSCSICC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIOSCSICC); 1549 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[ qIdx];1550 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[ qIdx];1551 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[idxQueue]; 1552 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxQueue]; 1551 1553 1552 1554 if (pThread->enmState == PDMTHREADSTATE_INITIALIZING) … … 1555 1557 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 1556 1558 { 1557 if (!pWorkerR3->cRedoDescs && virtioCoreQueueIsEmpty(pDevIns, &pThis->Virtio, qIdx))1559 if (!pWorkerR3->cRedoDescs && IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, idxQueue)) 1558 1560 { 1559 1561 /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */ … … 1562 1564 if (!fNotificationSent) 1563 1565 { 1564 Log6Func(("%s worker sleeping...\n", VIRTQNAME( qIdx)));1566 Log6Func(("%s worker sleeping...\n", VIRTQNAME(idxQueue))); 1565 1567 Assert(ASMAtomicReadBool(&pWorker->fSleeping)); 1566 1568 int rc = PDMDevHlpSUPSemEventWaitNoResume(pDevIns, pWorker->hEvtProcess, RT_INDEFINITE_WAIT); … … 1570 1572 if (rc == VERR_INTERRUPTED) 1571 1573 continue; 1572 Log6Func(("%s worker woken\n", VIRTQNAME( qIdx)));1574 Log6Func(("%s worker woken\n", VIRTQNAME(idxQueue))); 1573 1575 ASMAtomicWriteBool(&pWorker->fNotified, false); 1574 1576 } … … 1576 1578 } 1577 1579 1578 if (!pThis->afQueueAttached[ qIdx])1580 if (!pThis->afQueueAttached[idxQueue]) 1579 1581 { 1580 LogFunc(("%s queue not attached, worker aborting...\n", VIRTQNAME( qIdx)));1582 LogFunc(("%s queue not attached, worker aborting...\n", VIRTQNAME(idxQueue))); 1581 1583 break; 1582 1584 } … … 1587 1589 { 1588 1590 PVIRTIO_DESC_CHAIN_T pDescChain; 1589 int rc = virtioCoreR3DescChainGet(pDevIns, &pThis->Virtio, qIdx,1591 int rc = virtioCoreR3DescChainGet(pDevIns, &pThis->Virtio, idxQueue, 1590 1592 pWorkerR3->auRedoDescs[i], &pDescChain); 1591 1593 if (RT_FAILURE(rc)) 1592 1594 LogRel(("Error fetching desc chain to redo, %Rrc", rc)); 1593 1595 1594 rc = virtioScsiR3ReqSubmit(pDevIns, pThis, pThisCC, qIdx, pDescChain);1596 rc = virtioScsiR3ReqSubmit(pDevIns, pThis, pThisCC, idxQueue, pDescChain); 1595 1597 if (RT_FAILURE(rc)) 1596 1598 LogRel(("Error submitting req packet, resetting %Rrc", rc)); … … 1600 1602 pWorkerR3->cRedoDescs = 0; 1601 1603 1602 Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME( qIdx)));1604 Log6Func(("fetching next descriptor chain from %s\n", VIRTQNAME(idxQueue))); 1603 1605 PVIRTIO_DESC_CHAIN_T pDescChain = NULL; 1604 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, qIdx, &pDescChain, true);1606 int rc = virtioCoreR3QueueGet(pDevIns, &pThis->Virtio, idxQueue, &pDescChain, true); 1605 1607 if (rc == VERR_NOT_AVAILABLE) 1606 1608 { 1607 Log6Func(("Nothing found in %s\n", VIRTQNAME( qIdx)));1609 Log6Func(("Nothing found in %s\n", VIRTQNAME(idxQueue))); 1608 1610 continue; 1609 1611 } 1610 1612 1611 1613 AssertRC(rc); 1612 if ( qIdx== CONTROLQ_IDX)1613 virtioScsiR3Ctrl(pDevIns, pThis, pThisCC, qIdx, pDescChain);1614 if (idxQueue == CONTROLQ_IDX) 1615 virtioScsiR3Ctrl(pDevIns, pThis, pThisCC, idxQueue, pDescChain); 1614 1616 else /* request queue index */ 1615 1617 { 1616 rc = virtioScsiR3ReqSubmit(pDevIns, pThis, pThisCC, qIdx, pDescChain);1618 rc = virtioScsiR3ReqSubmit(pDevIns, pThis, pThisCC, idxQueue, pDescChain); 1617 1619 if (RT_FAILURE(rc)) 1618 1620 LogRel(("Error submitting req packet, resetting %Rrc", rc)); … … 1964 1966 1965 1967 virtioScsiSetVirtqNames(pThis); 1966 for (int qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)1967 pHlp->pfnSSMGetBool(pSSM, &pThis->afQueueAttached[ qIdx]);1968 for (int idxQueue = 0; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 1969 pHlp->pfnSSMGetBool(pSSM, &pThis->afQueueAttached[idxQueue]); 1968 1970 1969 1971 pHlp->pfnSSMGetU32(pSSM, &pThis->virtioScsiConfig.uNumQueues); … … 1999 2001 rc = pHlp->pfnSSMGetU16(pSSM, &cReqsRedo); 2000 2002 AssertRCReturn(rc, rc); 2001 AssertReturn(cReqsRedo < VIRTQ_MAX_ SIZE,2003 AssertReturn(cReqsRedo < VIRTQ_MAX_ENTRIES, 2002 2004 pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS, 2003 2005 N_("Bad count of I/O transactions to re-do in saved state (%#x, max %#x - 1)"), 2004 cReqsRedo, VIRTQ_MAX_ SIZE));2005 2006 for (uint16_t qIdx = VIRTQ_REQ_BASE; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)2006 cReqsRedo, VIRTQ_MAX_ENTRIES)); 2007 2008 for (uint16_t idxQueue = VIRTQ_REQ_BASE; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 2007 2009 { 2008 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[ qIdx];2010 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxQueue]; 2009 2011 pWorkerR3->cRedoDescs = 0; 2010 2012 } … … 2012 2014 for (int i = 0; i < cReqsRedo; i++) 2013 2015 { 2014 uint16_t qIdx;2015 rc = pHlp->pfnSSMGetU16(pSSM, & qIdx);2016 uint16_t idxQueue; 2017 rc = pHlp->pfnSSMGetU16(pSSM, &idxQueue); 2016 2018 AssertRCReturn(rc, rc); 2017 AssertReturn( qIdx< VIRTIOSCSI_QUEUE_CNT,2019 AssertReturn(idxQueue < VIRTIOSCSI_QUEUE_CNT, 2018 2020 pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS, 2019 2021 N_("Bad queue index for re-do in saved state (%#x, max %#x)"), 2020 qIdx, VIRTIOSCSI_QUEUE_CNT - 1));2022 idxQueue, VIRTIOSCSI_QUEUE_CNT - 1)); 2021 2023 2022 2024 uint16_t idxHead; 2023 2025 rc = pHlp->pfnSSMGetU16(pSSM, &idxHead); 2024 2026 AssertRCReturn(rc, rc); 2025 AssertReturn(idxHead < VIRTQ_MAX_ SIZE,2027 AssertReturn(idxHead < VIRTQ_MAX_ENTRIES, 2026 2028 pHlp->pfnSSMSetLoadError(pSSM, VERR_SSM_DATA_UNIT_FORMAT_CHANGED, RT_SRC_POS, 2027 2029 N_("Bad queue element index for re-do in saved state (%#x, max %#x)"), 2028 idxHead, VIRTQ_MAX_ SIZE- 1));2029 2030 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[ qIdx];2030 idxHead, VIRTQ_MAX_ENTRIES - 1)); 2031 2032 PVIRTIOSCSIWORKERR3 pWorkerR3 = &pThisCC->aWorkers[idxQueue]; 2031 2033 pWorkerR3->auRedoDescs[pWorkerR3->cRedoDescs++] = idxHead; 2032 pWorkerR3->cRedoDescs %= VIRTQ_MAX_ SIZE;2034 pWorkerR3->cRedoDescs %= VIRTQ_MAX_ENTRIES; 2033 2035 } 2034 2036 } … … 2042 2044 * Nudge request queue workers 2043 2045 */ 2044 for (int qIdx = VIRTQ_REQ_BASE; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)2045 { 2046 if (pThis->afQueueAttached[ qIdx])2046 for (int idxQueue = VIRTQ_REQ_BASE; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 2047 { 2048 if (pThis->afQueueAttached[idxQueue]) 2047 2049 { 2048 LogFunc(("Waking %s worker.\n", VIRTQNAME( qIdx)));2049 int rc2 = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[ qIdx].hEvtProcess);2050 LogFunc(("Waking %s worker.\n", VIRTQNAME(idxQueue))); 2051 int rc2 = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[idxQueue].hEvtProcess); 2050 2052 AssertRCReturn(rc, rc2); 2051 2053 } … … 2066 2068 LogFunc(("SAVE EXEC!!\n")); 2067 2069 2068 for (int qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)2069 pHlp->pfnSSMPutBool(pSSM, pThis->afQueueAttached[ qIdx]);2070 for (int idxQueue = 0; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 2071 pHlp->pfnSSMPutBool(pSSM, pThis->afQueueAttached[idxQueue]); 2070 2072 2071 2073 pHlp->pfnSSMPutU32(pSSM, pThis->virtioScsiConfig.uNumQueues); … … 2114 2116 while(--cReqsRedo) 2115 2117 { 2116 pHlp->pfnSSMPutU16(pSSM, pReq-> qIdx);2118 pHlp->pfnSSMPutU16(pSSM, pReq->idxQueue); 2117 2119 pHlp->pfnSSMPutU16(pSSM, pReq->pDescChain->uHeadIdx); 2118 2120 … … 2332 2334 * be awake due to new reqs coming in. 2333 2335 */ 2334 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++)2335 { 2336 if (ASMAtomicReadBool(&pThis->aWorkers[ qIdx].fSleeping))2336 for (uint16_t idxQueue = 0; idxQueue < VIRTIOSCSI_REQ_QUEUE_CNT; idxQueue++) 2337 { 2338 if (ASMAtomicReadBool(&pThis->aWorkers[idxQueue].fSleeping)) 2337 2339 { 2338 Log6Func(("waking %s worker.\n", VIRTQNAME( qIdx)));2339 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[ qIdx].hEvtProcess);2340 Log6Func(("waking %s worker.\n", VIRTQNAME(idxQueue))); 2341 int rc = PDMDevHlpSUPSemEventSignal(pDevIns, pThis->aWorkers[idxQueue].hEvtProcess); 2340 2342 AssertRC(rc); 2341 2343 } … … 2411 2413 pThisCC->pMediaNotify = NULL; 2412 2414 2413 for (unsigned qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)2414 { 2415 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[ qIdx];2415 for (unsigned idxQueue = 0; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 2416 { 2417 PVIRTIOSCSIWORKER pWorker = &pThis->aWorkers[idxQueue]; 2416 2418 if (pWorker->hEvtProcess != NIL_SUPSEMEVENT) 2417 2419 { … … 2420 2422 } 2421 2423 2422 if (pThisCC->aWorkers[ qIdx].pThread)2424 if (pThisCC->aWorkers[idxQueue].pThread) 2423 2425 { 2424 2426 /* Destroy the thread. */ 2425 2427 int rcThread; 2426 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[ qIdx].pThread, &rcThread);2428 int rc = PDMDevHlpThreadDestroy(pDevIns, pThisCC->aWorkers[idxQueue].pThread, &rcThread); 2427 2429 if (RT_FAILURE(rc) || RT_FAILURE(rcThread)) 2428 2430 AssertMsgFailed(("%s Failed to destroythread rc=%Rrc rcThread=%Rrc\n", 2429 2431 __FUNCTION__, rc, rcThread)); 2430 pThisCC->aWorkers[ qIdx].pThread = NULL;2432 pThisCC->aWorkers[idxQueue].pThread = NULL; 2431 2433 } 2432 2434 } … … 2523 2525 2524 2526 /* Attach the queues and create worker threads for them: */ 2525 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_QUEUE_CNT; qIdx++)2526 { 2527 rc = virtioCoreR3QueueAttach(&pThis->Virtio, qIdx, VIRTQNAME(qIdx));2527 for (uint16_t idxQueue = 0; idxQueue < VIRTIOSCSI_QUEUE_CNT; idxQueue++) 2528 { 2529 rc = virtioCoreR3QueueAttach(&pThis->Virtio, idxQueue, VIRTQNAME(idxQueue)); 2528 2530 if (RT_FAILURE(rc)) 2529 2531 continue; 2530 if ( qIdx == CONTROLQ_IDX || IS_REQ_QUEUE(qIdx))2532 if (idxQueue == CONTROLQ_IDX || IS_REQ_QUEUE(idxQueue)) 2531 2533 { 2532 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->aWorkers[ qIdx].pThread,2533 (void *)(uintptr_t) qIdx, virtioScsiR3WorkerThread,2534 virtioScsiR3WorkerWakeUp, 0, RTTHREADTYPE_IO, VIRTQNAME( qIdx));2534 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->aWorkers[idxQueue].pThread, 2535 (void *)(uintptr_t)idxQueue, virtioScsiR3WorkerThread, 2536 virtioScsiR3WorkerWakeUp, 0, RTTHREADTYPE_IO, VIRTQNAME(idxQueue)); 2535 2537 if (rc != VINF_SUCCESS) 2536 2538 { 2537 LogRel(("Error creating thread for Virtual Queue %s: %Rrc\n", VIRTQNAME( qIdx), rc));2539 LogRel(("Error creating thread for Virtual Queue %s: %Rrc\n", VIRTQNAME(idxQueue), rc)); 2538 2540 return rc; 2539 2541 } 2540 2542 2541 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->aWorkers[ qIdx].hEvtProcess);2543 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->aWorkers[idxQueue].hEvtProcess); 2542 2544 if (RT_FAILURE(rc)) 2543 2545 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 2544 2546 N_("DevVirtioSCSI: Failed to create SUP event semaphore")); 2545 2547 } 2546 pThis->afQueueAttached[ qIdx] = true;2548 pThis->afQueueAttached[idxQueue] = true; 2547 2549 } 2548 2550 -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r84509 r84774 22 22 #define LOG_GROUP LOG_GROUP_DEV_VIRTIO 23 23 24 #include <VBox/log.h>25 #include <VBox/msi.h>26 #include <VBox/AssertGuest.h>27 #include <iprt/param.h>28 24 #include <iprt/assert.h> 29 25 #include <iprt/uuid.h> 30 26 #include <iprt/mem.h> 27 #include <iprt/sg.h> 31 28 #include <iprt/assert.h> 32 #include <iprt/sg.h>33 29 #include <iprt/string.h> 30 #include <iprt/param.h> 31 #include <iprt/types.h> 32 #include <VBox/log.h> 33 #include <VBox/msi.h> 34 #include <iprt/types.h> 35 #include <VBox/AssertGuest.h> 34 36 #include <VBox/vmm/pdmdev.h> 35 37 #include "Virtio_1_0.h" … … 42 44 #define VIRTQNAME(a_pVirtio, a_idxQueue) ((a_pVirtio)->virtqState[(a_idxQueue)].szVirtqName) 43 45 #define IS_DRIVER_OK(a_pVirtio) ((a_pVirtio)->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) 46 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq) \ 47 (virtioCoreQueueAvailCount(pDevIns, pVirtio, pVirtq) == 0) 44 48 45 49 /** … … 50 54 * @param[in] a_offAccess The offset into the MMIO bar of the access. 51 55 * @param[in] a_cbAccess The access size. 52 * @param[out] a_off IntraVar The variable to return the intra-capability56 * @param[out] a_offsetInMbr The variable to return the intra-capability 53 57 * offset into. ASSUMES this is uint32_t. 54 58 * @param[in] a_LocCapData The capability location info. 55 59 */ 56 #define MATCHES_VIRTIO_CAP_STRUCT(a_offAccess, a_cbAccess, a_off IntraVar, a_LocCapData) \57 ( ((a_off IntraVar) = (uint32_t)((a_offAccess) - (a_LocCapData).offMmio)) < (uint32_t)(a_LocCapData).cbMmio \58 && (a_off IntraVar) + (uint32_t)(a_cbAccess) <= (uint32_t)(a_LocCapData).cbMmio )60 #define MATCHES_VIRTIO_CAP_STRUCT(a_offAccess, a_cbAccess, a_offsetInMbr, a_LocCapData) \ 61 ( ((a_offsetInMbr) = (uint32_t)((a_offAccess) - (a_LocCapData).offMmio)) < (uint32_t)(a_LocCapData).cbMmio \ 62 && (a_offsetInMbr) + (uint32_t)(a_cbAccess) <= (uint32_t)(a_LocCapData).cbMmio ) 59 63 60 64 … … 131 135 /* Internal Functions */ 132 136 133 static void virtio NotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue);137 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 134 138 static int virtioKick(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint8_t uCause, uint16_t uVec); 135 139 … … 190 194 } 191 195 192 DECLINLINE(bool) virtqIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)193 {194 uint16_t uAvailGuestIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue);195 bool fEmpty = uAvailGuestIdx == pVirtio->virtqState[idxQueue].uAvailIdx;196 197 Log6Func(("%s idx=%u, shadow idx=%u (%s)\n",198 VIRTQNAME(pVirtio, idxQueue), uAvailGuestIdx, pVirtio->virtqState[idxQueue].uAvailIdx,199 fEmpty ? "Queue empty" : "Queue has available descriptors"));200 return fEmpty;201 }202 203 196 DECLINLINE(uint16_t) virtioReadAvailRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 204 197 { … … 259 252 #endif 260 253 261 262 254 #ifdef IN_RING3 263 255 DECLINLINE(uint16_t) virtioReadUsedRingFlags(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) … … 279 271 &uAvailEventIdx, sizeof(uAvailEventIdx)); 280 272 } 273 274 281 275 #endif 276 277 DECLINLINE(uint16_t) virtioCoreQueueAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, PVIRTQSTATE pVirtq) 278 { 279 uint16_t uIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, pVirtq->idxQueue); 280 uint16_t uShadow = pVirtq->uAvailIdxShadow; 281 282 uint16_t uDelta; 283 if (uIdx < uShadow) 284 uDelta = (uIdx + VIRTQ_MAX_ENTRIES) - uShadow; 285 else 286 uDelta = uIdx - uShadow; 287 288 LogFunc(("%s has %u %s (idx=%u shadow=%u)\n", 289 VIRTQNAME(pVirtio, pVirtq->idxQueue), uDelta, uDelta == 1 ? "entry" : "entries", 290 uIdx, uShadow)); 291 292 return uDelta; 293 } 294 /** 295 * Get count of new (e.g. pending) elements in available ring. 296 * 297 * @param pDevIns The device instance. 298 * @param pVirtio Pointer to the shared virtio state. 299 * @param idxQueue Queue number 300 * 301 * @returns how many entries have been added to ring as a delta of the consumer's 302 * avail index and the queue's guest-side current avail index. 303 */ 304 uint16_t virtioCoreQueueAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 305 { 306 if (!IS_DRIVER_OK(pVirtio) || !pVirtio->uQueueEnable[idxQueue]) 307 { 308 LogRelFunc(("Driver not ready or queue not enabled\n")); 309 return 0; 310 } 311 return virtioCoreQueueAvailCount(pDevIns, pVirtio, &pVirtio->virtqState[idxQueue]); 312 } 313 282 314 283 315 /** @} */ … … 294 326 if (cSegs && paSegs) 295 327 { 296 pGcSgBuf-> gcPhysCur = paSegs[0].gcPhys;328 pGcSgBuf->GCPhysCur = paSegs[0].GCPhys; 297 329 pGcSgBuf->cbSegLeft = paSegs[0].cbSeg; 298 330 } 299 331 else 300 332 { 301 pGcSgBuf-> gcPhysCur = 0;333 pGcSgBuf->GCPhysCur = 0; 302 334 pGcSgBuf->cbSegLeft = 0; 303 335 } … … 319 351 320 352 AssertMsg( pGcSgBuf->cbSegLeft <= 128 * _1M 321 && (RTGCPHYS)pGcSgBuf-> gcPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys322 && (RTGCPHYS)pGcSgBuf-> gcPhysCur + pGcSgBuf->cbSegLeft <=323 (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg]. gcPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg,324 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf-> gcPhysCur=%p pGcSgBuf->cbSegLeft=%zd "325 "pGcSgBuf->paSegs[%d]. gcPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n",326 pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf-> gcPhysCur, pGcSgBuf->cbSegLeft,327 pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg]. gcPhys, pGcSgBuf->idxSeg,353 && (RTGCPHYS)pGcSgBuf->GCPhysCur >= (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys 354 && (RTGCPHYS)pGcSgBuf->GCPhysCur + pGcSgBuf->cbSegLeft <= 355 (RTGCPHYS)pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys + pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg, 356 ("pGcSgBuf->idxSeg=%d pGcSgBuf->cSegs=%d pGcSgBuf->GCPhysCur=%p pGcSgBuf->cbSegLeft=%zd " 357 "pGcSgBuf->paSegs[%d].GCPhys=%p pGcSgBuf->paSegs[%d].cbSeg=%zd\n", 358 pGcSgBuf->idxSeg, pGcSgBuf->cSegs, pGcSgBuf->GCPhysCur, pGcSgBuf->cbSegLeft, 359 pGcSgBuf->idxSeg, pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys, pGcSgBuf->idxSeg, 328 360 pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg)); 329 361 330 362 cbData = RT_MIN(*pcbData, pGcSgBuf->cbSegLeft); 331 pGcBuf = pGcSgBuf-> gcPhysCur;363 pGcBuf = pGcSgBuf->GCPhysCur; 332 364 pGcSgBuf->cbSegLeft -= cbData; 333 365 if (!pGcSgBuf->cbSegLeft) … … 337 369 if (pGcSgBuf->idxSeg < pGcSgBuf->cSegs) 338 370 { 339 pGcSgBuf-> gcPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].gcPhys;371 pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].GCPhys; 340 372 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[pGcSgBuf->idxSeg].cbSeg; 341 373 } … … 343 375 } 344 376 else 345 pGcSgBuf-> gcPhysCur = pGcSgBuf->gcPhysCur + cbData;377 pGcSgBuf->GCPhysCur = pGcSgBuf->GCPhysCur + cbData; 346 378 347 379 return pGcBuf; … … 355 387 if (pGcSgBuf->cSegs) 356 388 { 357 pGcSgBuf-> gcPhysCur = pGcSgBuf->paSegs[0].gcPhys;389 pGcSgBuf->GCPhysCur = pGcSgBuf->paSegs[0].GCPhys; 358 390 pGcSgBuf->cbSegLeft = pGcSgBuf->paSegs[0].cbSeg; 359 391 } 360 392 else 361 393 { 362 pGcSgBuf-> gcPhysCur = 0;394 pGcSgBuf->GCPhysCur = 0; 363 395 pGcSgBuf->cbSegLeft = 0; 364 396 } … … 402 434 } 403 435 404 #ifdef LOG_ENABLED 405 406 void virtioPrintFeatures(VIRTIOCORE *pVirtio) 407 { 408 #ifdef LOG_ENABLED 436 #ifdef IN_RING3 437 void virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp) 438 { 409 439 static struct 410 440 { … … 431 461 isOffered ? "+" : "-", isNegotiated ? "x" : " ", s_aFeatures[i].pcszDesc); 432 462 } 433 Log3(("VirtIO Features Configuration\n\n" 434 " Offered Accepted Feature Description\n" 435 " ------- -------- ------- -----------\n" 436 "%s\n", pszBuf)); 463 if (pHlp) 464 pHlp->pfnPrintf(pHlp, "VirtIO Core Features Configuration\n\n" 465 " Offered Accepted Feature Description\n" 466 " ------- -------- ------- -----------\n" 467 "%s\n", pszBuf); 468 #ifdef LOG_ENABLED 469 else 470 Log3(("VirtIO Core Features Configuration\n\n" 471 " Offered Accepted Feature Description\n" 472 " ------- -------- ------- -----------\n" 473 "%s\n", pszBuf)); 474 #endif 437 475 RTMemFree(pszBuf); 438 439 #else /* !LOG_ENABLED */ 440 RT_NOREF3(pThis, fFeatures, pcszText); 441 #endif /* !LOG_ENABLED */ 442 } 443 444 445 /** 476 } 477 #endif 478 479 #ifdef LOG_ENABLED 480 /** 481 * Debug assist for consumer device code. 446 482 * Does a formatted hex dump using Log(()), recommend using VIRTIO_HEX_DUMP() macro to 447 483 * control enabling of logging efficiently. … … 455 491 void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle) 456 492 { 493 #define ADJCURSOR(cb) pszOut += cb; cbRemain -= cb; 494 int cbPrint = 0, cbRemain = ((cb / 16) + 1) * 80; 495 char *pszBuf = (char *)RTMemAllocZ(cbRemain), *pszOut = pszBuf; 496 AssertMsgReturnVoid(pszBuf, ("Out of Memory")); 457 497 if (pszTitle) 458 Log(("%s [%d bytes]:\n", pszTitle, cb)); 498 { 499 cbPrint = RTStrPrintf(pszOut, cbRemain, "%s [%d bytes]:\n", pszTitle, cb); 500 ADJCURSOR(cbPrint); 501 } 459 502 for (uint32_t row = 0; row < RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++) 460 503 { 461 Log(("%04x: ", row * 16 + uBase)); /* line address */ 504 cbPrint = RTStrPrintf(pszOut, cbRemain, "%04x: ", row * 16 + uBase); /* line address */ 505 ADJCURSOR(cbPrint); 462 506 for (uint8_t col = 0; col < 16; col++) 463 507 { 464 508 uint32_t idx = row * 16 + col; 465 509 if (idx >= cb) 466 Log(("-- %s", (col + 1) % 8 ? "" : " "));510 cbPrint = RTStrPrintf(pszOut, cbRemain, "-- %s", (col + 1) % 8 ? "" : " "); 467 511 else 468 Log(("%02x %s", pv[idx], (col + 1) % 8 ? "" : " ")); 512 cbPrint = RTStrPrintf(pszOut, cbRemain, ("%02x %s", pv[idx], (col + 1) % 8 ? "" : " ")); 513 ADJCURSOR(cbPrint); 469 514 } 470 515 for (uint32_t idx = row * 16; idx < row * 16 + 16; idx++) 471 Log(("%c", (idx >= cb) ? ' ' : (pv[idx] >= 0x20 && pv[idx] <= 0x7e ? pv[idx] : '.'))); 472 Log(("\n")); 473 } 474 Log(("\n")); 516 { 517 cbPrint = RTStrPrintf(pszOut, cbRemain, "%c", (idx >= cb) ? ' ' : (pv[idx] >= 0x20 && pv[idx] <= 0x7e ? pv[idx] : '.')); 518 ADJCURSOR(cbPrint); 519 } 520 *pszOut++ = '\n'; 521 --cbRemain; 522 } 523 Log(("%s\n", pszBuf)); 524 RTMemFree(pszBuf); 475 525 RT_NOREF2(uBase, pv); 476 } 477 478 /** 526 #undef ADJCURSOR 527 } 528 529 /** 530 * Debug assist for consumer device code. 479 531 * Do a hex dump of memory in guest physical context 480 532 * 481 * @param gcPhys pointer to buffer to dump contents of533 * @param GCPhys pointer to buffer to dump contents of 482 534 * @param cb count of characters to dump from buffer 483 535 * @param uBase base address of per-row address prefixing of hex output … … 485 537 * provided text with value of cb to indicate size next to it. 486 538 */ 487 void virtioCoreGcPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS gcPhys, uint32_t cb, uint32_t uBase, const char *pszTitle) 488 { 539 void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle) 540 { 541 #define ADJCURSOR(cb) pszOut += cb; cbRemain -= cb; 542 int cbPrint = 0, cbRemain = ((cb / 16) + 1) * 80; 543 char *pszBuf = (char *)RTMemAllocZ(cbRemain), *pszOut = pszBuf; 544 AssertMsgReturnVoid(pszBuf, ("Out of Memory")); 489 545 if (pszTitle) 490 Log(("%s [%d bytes]:\n", pszTitle, cb)); 491 for (uint32_t row = 0; row < RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++) 546 { 547 cbPrint = RTStrPrintf(pszOut, cbRemain, "%s [%d bytes]:\n", pszTitle, cb); 548 ADJCURSOR(cbPrint); 549 } 550 for (uint16_t row = 0; row < (uint16_t)RT_MAX(1, (cb / 16) + 1) && row * 16 < cb; row++) 492 551 { 493 552 uint8_t c; 494 Log(("%04x: ", row * 16 + uBase)); /* line address */ 553 cbPrint = RTStrPrintf(pszOut, cbRemain, "%04x: ", row * 16 + uBase); /* line address */ 554 ADJCURSOR(cbPrint); 495 555 for (uint8_t col = 0; col < 16; col++) 496 556 { 497 557 uint32_t idx = row * 16 + col; 498 PDMDevHlpPCIPhysRead(pDevIns, gcPhys + idx, &c, 1);558 PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1); 499 559 if (idx >= cb) 500 Log(("-- %s", (col + 1) % 8 ? "" : " "));560 cbPrint = RTStrPrintf(pszOut, cbRemain, "-- %s", (col + 1) % 8 ? "" : " "); 501 561 else 502 Log(("%02x %s", c, (col + 1) % 8 ? "" : " ")); 503 } 504 for (uint32_t idx = row * 16; idx < row * 16 + 16; idx++) 505 { 506 PDMDevHlpPCIPhysRead(pDevIns, gcPhys + idx, &c, 1); 507 Log(("%c", (idx >= cb) ? ' ' : (c >= 0x20 && c <= 0x7e ? c : '.'))); 508 } 509 Log(("\n")); 510 } 511 Log(("\n")); 562 cbPrint = RTStrPrintf(pszOut, cbRemain, "%02x %s", c, (col + 1) % 8 ? "" : " "); 563 ADJCURSOR(cbPrint); 564 } 565 for (uint16_t idx = row * 16; idx < row * 16 + 16; idx++) 566 { 567 PDMDevHlpPCIPhysRead(pDevIns, GCPhys + idx, &c, 1); 568 cbPrint = RTStrPrintf(pszOut, cbRemain, "%c", (idx >= cb) ? ' ' : (c >= 0x20 && c <= 0x7e ? c : '.')); 569 ADJCURSOR(cbPrint); 570 } 571 *pszOut++ = '\n'; 572 --cbRemain; 573 } 574 Log(("%s\n", pszBuf)); 575 RTMemFree(pszBuf); 512 576 RT_NOREF(uBase); 577 #undef ADJCURSOR 513 578 } 514 579 #endif /* LOG_ENABLED */ … … 607 672 608 673 #ifdef IN_RING3 609 /** 610 * Allocate client context for client to work with VirtIO-provided with queue 674 675 void virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs) 676 { 677 RT_NOREF(pDevIns); 678 bool fNone = pszArgs && *pszArgs == '\0'; 679 bool fAll = pszArgs && (*pszArgs == 'a' || *pszArgs == 'A'); /* "all" */ 680 bool fBasic = pszArgs && (*pszArgs == 'b' || *pszArgs == 'B'); /* "basic" */ 681 bool fState = pszArgs && (*pszArgs == 's' || *pszArgs == 'S'); /* "state" */ 682 bool fPointers = pszArgs && (*pszArgs == 'p' || *pszArgs == 'P'); /* "pointers" */ 683 bool fQueues = pszArgs && (*pszArgs == 'q' || *pszArgs == 'Q'); /* "queues */ 684 RT_NOREF6(fNone, fAll, fBasic, fState, fPointers, fQueues); 685 pHlp->pfnPrintf(pHlp, ""); 686 687 } 688 689 void virtioCoreR3QueueInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxQueue) 690 { 691 RT_NOREF(pszArgs); 692 PVIRTIOCORE pVirtio = PDMDEVINS_2_DATA(pDevIns, PVIRTIOCORE); 693 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 694 695 // bool fDump = pszArgs && (*pszArgs == 'd' || *pszArgs == 'D'); /* "dump" (avail phys descriptor)" */ 696 697 uint16_t uAvailIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue); 698 uint16_t uAvailIdxShadow = pVirtq->uAvailIdxShadow; 699 700 uint16_t uUsedIdx = virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue); 701 uint16_t uUsedIdxShadow = pVirtq->uUsedIdxShadow; 702 703 PVIRTIO_DESC_CHAIN_T pDescChain; 704 705 bool fEmpty = IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq); 706 707 LogFunc(("%s, empty = %s\n", VIRTQNAME(pVirtio, idxQueue), fEmpty ? "true" : "false")); 708 709 int cSendSegs = 0, cReturnSegs = 0; 710 if (!fEmpty) 711 { 712 virtioCoreR3QueuePeek(pDevIns, pVirtio, idxQueue, &pDescChain); 713 cSendSegs = pDescChain->pSgPhysSend ? pDescChain->pSgPhysSend->cSegs : 0; 714 cReturnSegs = pDescChain->pSgPhysReturn ? pDescChain->pSgPhysReturn->cSegs : 0; 715 } 716 717 bool fAvailNoInterrupt = virtioReadAvailRingFlags(pDevIns, pVirtio, idxQueue) & VIRTQ_AVAIL_F_NO_INTERRUPT; 718 bool fUsedNoNotify = virtioReadUsedRingFlags(pDevIns, pVirtio, idxQueue) & VIRTQ_USED_F_NO_NOTIFY; 719 720 721 pHlp->pfnPrintf(pHlp, " queue enabled: ........... %s\n", pVirtio->uQueueEnable[idxQueue] ? "true" : "false"); 722 pHlp->pfnPrintf(pHlp, " size: .................... %d\n", pVirtio->uQueueSize[idxQueue]); 723 pHlp->pfnPrintf(pHlp, " notify offset: ........... %d\n", pVirtio->uQueueNotifyOff[idxQueue]); 724 if (pVirtio->fMsiSupport) 725 pHlp->pfnPrintf(pHlp, " MSIX vector: ....... %4.4x\n", pVirtio->uQueueMsixVector[idxQueue]); 726 pHlp->pfnPrintf(pHlp, "\n"); 727 pHlp->pfnPrintf(pHlp, " avail ring (%d entries):\n", uAvailIdx - uAvailIdxShadow); 728 pHlp->pfnPrintf(pHlp, " index: ................ %d\n", uAvailIdx); 729 pHlp->pfnPrintf(pHlp, " shadow: ............... %d\n", uAvailIdxShadow); 730 pHlp->pfnPrintf(pHlp, " flags: ................ %s\n", fAvailNoInterrupt ? "NO_INTERRUPT" : ""); 731 pHlp->pfnPrintf(pHlp, "\n"); 732 pHlp->pfnPrintf(pHlp, " used ring (%d entries):\n", uUsedIdx - uUsedIdxShadow); 733 pHlp->pfnPrintf(pHlp, " index: ................ %d\n", uUsedIdx); 734 pHlp->pfnPrintf(pHlp, " shadow: ............... %d\n", uUsedIdxShadow); 735 pHlp->pfnPrintf(pHlp, " flags: ................ %s\n", fUsedNoNotify ? "NO_NOTIFY" : ""); 736 pHlp->pfnPrintf(pHlp, "\n"); 737 if (!fEmpty) 738 { 739 pHlp->pfnPrintf(pHlp, " desc chain:\n"); 740 pHlp->pfnPrintf(pHlp, " head idx: ............. %d\n", uUsedIdx); 741 pHlp->pfnPrintf(pHlp, " segs: ................. %d\n", cSendSegs + cReturnSegs); 742 pHlp->pfnPrintf(pHlp, " refCnt ................ %d\n", pDescChain->cRefs); 743 pHlp->pfnPrintf(pHlp, "\n"); 744 pHlp->pfnPrintf(pHlp, " host-to-guest (%d bytes):\n", pDescChain->cbPhysSend); 745 pHlp->pfnPrintf(pHlp, " segs: .............. %d\n", cSendSegs); 746 if (cSendSegs) 747 { 748 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", pDescChain->pSgPhysSend->idxSeg); 749 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", pDescChain->pSgPhysSend->cbSegLeft); 750 } 751 pHlp->pfnPrintf(pHlp, "\n"); 752 pHlp->pfnPrintf(pHlp, " guest-to-host (%d bytes)\n", pDescChain->cbPhysReturn); 753 pHlp->pfnPrintf(pHlp, " segs: .............. %d\n", cReturnSegs); 754 if (cReturnSegs) 755 { 756 pHlp->pfnPrintf(pHlp, " index: ............. %d\n", pDescChain->pSgPhysReturn->idxSeg); 757 pHlp->pfnPrintf(pHlp, " unsent ............. %d\n", pDescChain->pSgPhysReturn->cbSegLeft); 758 } 759 } else 760 pHlp->pfnPrintf(pHlp, " No desc chains available\n"); 761 pHlp->pfnPrintf(pHlp, "\n"); 762 763 } 764 765 /** 766 * Allocate client context for client to work with VirtIO-#provided with queue 611 767 * 612 768 * @param pVirtio Pointer to the shared virtio state. … … 620 776 LogFunc(("%s\n", pcszName)); 621 777 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 622 pVirtq->uAvailIdx = 0; 623 pVirtq->uUsedIdx = 0; 624 pVirtq->fEventThresholdReached = false; 778 pVirtq->idxQueue = idxQueue; 779 pVirtq->uAvailIdxShadow = 0; 780 pVirtq->uUsedIdxShadow = 0; 781 pVirtq->fVirtqRingEventThreshold = false; 625 782 RTStrCopy(pVirtq->szVirtqName, sizeof(pVirtq->szVirtqName), pcszName); 626 783 return VINF_SUCCESS; … … 629 786 630 787 631 /**632 * Check if the associated queue is empty633 *634 * @param pDevIns The device instance (for reading).635 * @param pVirtio Pointer to the shared virtio state.636 * @param idxQueue Queue number637 *638 * @retval true Queue is empty or unavailable.639 * @retval false Queue is available and has entries640 */641 bool virtioCoreQueueIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)642 {643 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK)644 return virtqIsEmpty(pDevIns, pVirtio, idxQueue);645 LogFunc(("VirtIO not ready: Returning 'true' for queue empty\n"));646 return true;647 }648 649 788 #ifdef IN_RING3 650 651 789 652 790 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, … … 700 838 * the following aborts I/O if breach and employs a simple log throttling algorithm to notify. 701 839 */ 702 if (cSegsIn + cSegsOut >= VIRTQ_MAX_ SIZE)840 if (cSegsIn + cSegsOut >= VIRTQ_MAX_ENTRIES) 703 841 { 704 842 static volatile uint32_t s_cMessages = 0; … … 728 866 cbOut += desc.cb; 729 867 pSeg = &paSegsOut[cSegsOut++]; 730 } 731 732 pSeg->gcPhys = desc.GCPhysBuf; 868 if (LogIs11Enabled()) 869 { 870 virtioCoreGCPhysHexDump(pDevIns, desc.GCPhysBuf, desc.cb, 0, NULL); 871 Log(("\n")); 872 } 873 } 874 875 pSeg->GCPhys = desc.GCPhysBuf; 733 876 pSeg->cbSeg = desc.cb; 734 877 … … 822 965 * @param pVirtio Pointer to the shared virtio state. 823 966 * @param idxQueue Queue number 824 * @param fEnable dSelects notification mode (enabled or disabled)825 */ 826 void virtioCoreQueue SetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled)967 * @param fEnable Selects notification mode (enabled or disabled) 968 */ 969 void virtioCoreQueueNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnable) 827 970 { 828 971 if (pVirtio->uDeviceStatus & VIRTIO_STATUS_DRIVER_OK) … … 830 973 uint16_t fFlags = virtioReadUsedRingFlags(pVirtio->pDevInsR3, pVirtio, idxQueue); 831 974 832 if (fEnable d)975 if (fEnable) 833 976 fFlags &= ~ VIRTQ_USED_F_NO_NOTIFY; 834 977 else … … 855 998 } 856 999 } 857 /** 858 * Get count of new (e.g. pending) elements in available ring. 859 * 860 * @param pDevIns The device instance. 861 * @param pVirtio Pointer to the shared virtio state. 862 * @param idxQueue Queue number 863 * 864 * @returns how many entries have been added to ring as a delta of the consumer's 865 * avail index and the queue's guest-side current avail index. 866 */ 867 int virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 868 { 869 uint16_t uAvailRingIdx = virtioReadAvailRingIdx(pDevIns, pVirtio, idxQueue); 870 uint16_t uNextAvailIdx = pVirtio->virtqState[idxQueue].uAvailIdx; 871 uint16_t uDelta = uAvailRingIdx - uNextAvailIdx; 872 if (uAvailRingIdx > uNextAvailIdx) 873 return uDelta; 874 return VIRTQ_MAX_CNT + uDelta; 875 } 1000 1001 1002 876 1003 /** 877 1004 * Fetches descriptor chain using avail ring of indicated queue and converts the descriptor … … 919 1046 ("Guest driver not in ready state.\n"), VERR_INVALID_STATE); 920 1047 921 if ( virtioCoreQueueIsEmpty(pVirtio->pDevInsR3, pVirtio, idxQueue))1048 if (IS_VIRTQ_EMPTY(pVirtio->pDevInsR3, pVirtio, pVirtq)) 922 1049 return VERR_NOT_AVAILABLE; 923 1050 924 Log 2Func(("%s avail_idx=%u\n", pVirtq->szVirtqName, pVirtq->uAvailIdx));925 pVirtq->uAvailIdx ++;1051 Log6Func(("%s avail shadow idx: %u\n", pVirtq->szVirtqName, pVirtq->uAvailIdxShadow)); 1052 pVirtq->uAvailIdxShadow++; 926 1053 927 1054 return VINF_SUCCESS; … … 956 1083 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 957 1084 958 if ( virtqIsEmpty(pDevIns, pVirtio, idxQueue))1085 if (IS_VIRTQ_EMPTY(pDevIns, pVirtio, pVirtq)) 959 1086 return VERR_NOT_AVAILABLE; 960 1087 961 uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, idxQueue, pVirtq->uAvailIdx );1088 uint16_t uHeadIdx = virtioReadAvailDescIdx(pDevIns, pVirtio, idxQueue, pVirtq->uAvailIdxShadow); 962 1089 963 1090 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 964 virtioWriteUsedAvailEvent(pDevIns,pVirtio, idxQueue, pVirtq->uAvailIdx + 1);1091 virtioWriteUsedAvailEvent(pDevIns,pVirtio, idxQueue, pVirtq->uAvailIdxShadow + 1); 965 1092 966 1093 if (fRemove) 967 pVirtq->uAvailIdx ++;1094 pVirtq->uAvailIdxShadow++; 968 1095 969 1096 int rc = virtioCoreR3DescChainGet(pDevIns, pVirtio, idxQueue, uHeadIdx, ppDescChain); … … 1034 1161 cbCopy = RT_MIN(pSgVirtReturn->cbSegLeft, pSgPhysReturn->cbSegLeft); 1035 1162 Assert(cbCopy > 0); 1036 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn-> gcPhysCur, pSgVirtReturn->pvSegCur, cbCopy);1163 PDMDevHlpPhysWrite(pDevIns, (RTGCPHYS)pSgPhysReturn->GCPhysCur, pSgVirtReturn->pvSegCur, cbCopy); 1037 1164 RTSgBufAdvance(pSgVirtReturn, cbCopy); 1038 1165 virtioCoreSgBufAdvance(pSgPhysReturn, cbCopy); … … 1048 1175 /* If this write-ahead crosses threshold where the driver wants to get an event flag it */ 1049 1176 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 1050 if (pVirtq->uUsedIdx == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue))1051 pVirtq->f EventThresholdReached = true;1177 if (pVirtq->uUsedIdxShadow == virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue)) 1178 pVirtq->fVirtqRingEventThreshold = true; 1052 1179 1053 1180 /* 1054 1181 * Place used buffer's descriptor in used ring but don't update used ring's slot index. 1055 1182 * That will be done with a subsequent client call to virtioCoreQueueSync() */ 1056 virtioWriteUsedElem(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdx ++, pDescChain->uHeadIdx, (uint32_t)cbTotal);1183 virtioWriteUsedElem(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdxShadow++, pDescChain->uHeadIdx, (uint32_t)cbTotal); 1057 1184 1058 1185 if (pSgVirtReturn) … … 1061 1188 1062 1189 Log6Func(("Write ahead used_idx=%u, %s used_idx=%u\n", 1063 pVirtq->uUsedIdx , VIRTQNAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue)));1190 pVirtq->uUsedIdxShadow, VIRTQNAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue))); 1064 1191 1065 1192 return VINF_SUCCESS; … … 1087 1214 int virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 1088 1215 { 1089 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState));1216 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState)); 1090 1217 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 1091 1218 … … 1094 1221 1095 1222 Log6Func(("Updating %s used_idx from %u to %u\n", 1096 VIRTQNAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue), pVirtq->uUsedIdx ));1097 1098 virtioWriteUsedRingIdx(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdx );1099 virtio NotifyGuestDriver(pDevIns, pVirtio, idxQueue);1223 VIRTQNAME(pVirtio, idxQueue), virtioReadUsedRingIdx(pDevIns, pVirtio, idxQueue), pVirtq->uUsedIdxShadow)); 1224 1225 virtioWriteUsedRingIdx(pDevIns, pVirtio, idxQueue, pVirtq->uUsedIdxShadow); 1226 virtioCoreNotifyGuestDriver(pDevIns, pVirtio, idxQueue); 1100 1227 1101 1228 return VINF_SUCCESS; 1102 1229 } 1103 1230 1104 /** 1105 */ 1106 static void virtioQueueNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx) 1231 1232 /** 1233 */ 1234 static void virtioCoreQueueNotified(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, uint16_t uNotifyIdx) 1107 1235 { 1108 1236 … … 1119 1247 1120 1248 AssertReturnVoid(idxQueue < RT_ELEMENTS(pVirtio->virtqState)); 1121 Log6Func(("%s\n", pVirtio->virtqState[idxQueue].szVirtqName)); 1249 Log6Func(("%s (desc chains: %u)\n", 1250 pVirtio->virtqState[idxQueue].szVirtqName, 1251 virtioCoreQueueAvailCount(pDevIns, pVirtio, idxQueue))); 1122 1252 1123 1253 /* Inform client */ … … 1136 1266 * @param idxQueue Queue to check for guest interrupt handling preference 1137 1267 */ 1138 static void virtio NotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue)1268 static void virtioCoreNotifyGuestDriver(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue) 1139 1269 { 1140 1270 … … 1150 1280 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 1151 1281 { 1152 if (pVirtq->f EventThresholdReached)1282 if (pVirtq->fVirtqRingEventThreshold) 1153 1283 { 1154 1284 #ifdef IN_RING3 … … 1157 1287 #endif 1158 1288 virtioKick(pDevIns, pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uQueueMsixVector[idxQueue]); 1159 pVirtq->f EventThresholdReached = false;1289 pVirtq->fVirtqRingEventThreshold = false; 1160 1290 return; 1161 1291 } 1162 1292 #ifdef IN_RING3 1163 Log6Func(("...skip pinginterrupt %s, VIRTIO_F_EVENT_IDX set but threshold (%d) not reached (%d)\n",1164 VIRTQNAME(pVirtio, idxQueue),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue), pVirtq->uUsedIdx ));1293 Log6Func(("...skip interrupt %s, VIRTIO_F_EVENT_IDX set but threshold (%d) not reached (%d)\n", 1294 VIRTQNAME(pVirtio, idxQueue),(uint16_t)virtioReadAvailUsedEvent(pDevIns, pVirtio, idxQueue), pVirtq->uUsedIdxShadow)); 1165 1295 #endif 1166 1296 } … … 1173 1303 return; 1174 1304 } 1175 Log6Func(("...skipping interrupt , queue %s, Guest flagged VIRTQ_AVAIL_F_NO_INTERRUPT for queue\n",1305 Log6Func(("...skipping interrupt for %s (guest set VIRTQ_AVAIL_F_NO_INTERRUPT)\n", 1176 1306 VIRTQNAME(pVirtio, idxQueue))); 1177 1307 } … … 1223 1353 Assert(idxQueue < RT_ELEMENTS(pVirtio->virtqState)); 1224 1354 PVIRTQSTATE pVirtq = &pVirtio->virtqState[idxQueue]; 1225 pVirtq->uAvailIdx = 0;1226 pVirtq->uUsedIdx = 0;1227 pVirtq->f EventThresholdReached = false;1355 pVirtq->uAvailIdxShadow = 0; 1356 pVirtq->uUsedIdxShadow = 0; 1357 pVirtq->fVirtqRingEventThreshold = false; 1228 1358 pVirtio->uQueueEnable[idxQueue] = false; 1229 pVirtio->uQueueSize[idxQueue] = VIRTQ_MAX_ SIZE;1359 pVirtio->uQueueSize[idxQueue] = VIRTQ_MAX_ENTRIES; 1230 1360 pVirtio->uQueueNotifyOff[idxQueue] = idxQueue; 1231 1361 pVirtio->uQueueMsixVector[idxQueue] = idxQueue + 2; … … 1314 1444 1315 1445 #ifdef LOG_ENABLED 1316 # define LOG_COMMON_CFG_ACCESS(member, a_offIntra) \1446 # define LOG_COMMON_CFG_ACCESS(member, uOffset) \ 1317 1447 if (LogIs7Enabled()) { \ 1318 1448 virtioCoreLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \ 1319 pv, cb, a_offIntra, fWrite, false, 0); \1320 } 1321 # define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) \1449 pv, cb, uOffset, fWrite, false, 0); \ 1450 } 1451 # define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, uOffset) \ 1322 1452 if (LogIs7Enabled()) { \ 1323 1453 virtioCoreLogMappedIoValue(__FUNCTION__, #member, RT_SIZEOFMEMB(VIRTIO_PCI_COMMON_CFG_T, member), \ 1324 pv, cb, a_offIntra, fWrite, true, idx); \1454 pv, cb, uOffset, fWrite, true, idx); \ 1325 1455 } 1326 1456 #else 1327 # define LOG_COMMON_CFG_ACCESS(member, a_offIntra) do { } while (0)1328 # define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, a_offIntra) do { } while (0)1457 # define LOG_COMMON_CFG_ACCESS(member, uOffset) do { } while (0) 1458 # define LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, uOffset) do { } while (0) 1329 1459 #endif 1330 1460 … … 1332 1462 do \ 1333 1463 { \ 1334 uint32_t offIntra= offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \1464 uint32_t uOffset = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ 1335 1465 if (fWrite) \ 1336 memcpy((char *)&pVirtio->member + offIntra, (const char *)pv, cb); \1466 memcpy((char *)&pVirtio->member + uOffset, (const char *)pv, cb); \ 1337 1467 else \ 1338 memcpy(pv, (const char *)&pVirtio->member + offIntra, cb); \1339 LOG_COMMON_CFG_ACCESS(member, offIntra); \1468 memcpy(pv, (const char *)&pVirtio->member + uOffset, cb); \ 1469 LOG_COMMON_CFG_ACCESS(member, uOffset); \ 1340 1470 } while(0) 1341 1471 … … 1343 1473 do \ 1344 1474 { \ 1345 uint32_t offIntra= offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \1475 uint32_t uOffset = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ 1346 1476 if (fWrite) \ 1347 memcpy((char *)&pVirtio->member[idx] + offIntra, pv, cb); \1477 memcpy((char *)&pVirtio->member[idx] + uOffset, pv, cb); \ 1348 1478 else \ 1349 memcpy(pv, (const char *)&pVirtio->member[idx] + offIntra, cb); \1350 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \1479 memcpy(pv, (const char *)&pVirtio->member[idx] + uOffset, cb); \ 1480 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, uOffset); \ 1351 1481 } while(0) 1352 1482 … … 1354 1484 do \ 1355 1485 { \ 1356 uint32_t offIntra= offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \1486 uint32_t uOffset = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ 1357 1487 if (fWrite) \ 1358 1488 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s\n", #member)); \ 1359 1489 else \ 1360 1490 { \ 1361 memcpy(pv, (const char *)&pVirtio->member + offIntra, cb); \1362 LOG_COMMON_CFG_ACCESS(member, offIntra); \1491 memcpy(pv, (const char *)&pVirtio->member + uOffset, cb); \ 1492 LOG_COMMON_CFG_ACCESS(member, uOffset); \ 1363 1493 } \ 1364 1494 } while(0) … … 1367 1497 do \ 1368 1498 { \ 1369 uint32_t offIntra= offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \1499 uint32_t uOffset = offCfg - RT_OFFSETOF(VIRTIO_PCI_COMMON_CFG_T, member); \ 1370 1500 if (fWrite) \ 1371 1501 LogFunc(("Guest attempted to write readonly virtio_pci_common_cfg.%s[%d]\n", #member, idx)); \ 1372 1502 else \ 1373 1503 { \ 1374 memcpy(pv, (char const *)&pVirtio->member[idx] + offIntra, cb); \1375 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, offIntra); \1504 memcpy(pv, (char const *)&pVirtio->member[idx] + uOffset, cb); \ 1505 LOG_COMMON_CFG_ACCESS_INDEXED(member, idx, uOffset); \ 1376 1506 } \ 1377 1507 } while(0) … … 1581 1711 1582 1712 1583 uint32_t offIntra;1584 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocDeviceCap))1713 uint32_t uOffset; 1714 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocDeviceCap)) 1585 1715 { 1586 1716 #ifdef IN_RING3 … … 1588 1718 * Callback to client to manage device-specific configuration. 1589 1719 */ 1590 VBOXSTRICTRC rcStrict = pVirtioCC->pfnDevCapRead(pDevIns, offIntra, pv, cb);1720 VBOXSTRICTRC rcStrict = pVirtioCC->pfnDevCapRead(pDevIns, uOffset, pv, cb); 1591 1721 1592 1722 /* … … 1595 1725 * order to maintain the config generation (see VirtIO 1.0 spec, section 4.1.4.3.1) 1596 1726 */ 1597 bool fDevSpecificFieldChanged = RT_BOOL(memcmp(pVirtioCC->pbDevSpecificCfg + offIntra,1598 pVirtioCC->pbPrevDevSpecificCfg + offIntra,1599 RT_MIN(cb, pVirtioCC->cbDevSpecificCfg - offIntra)));1727 bool fDevSpecificFieldChanged = RT_BOOL(memcmp(pVirtioCC->pbDevSpecificCfg + uOffset, 1728 pVirtioCC->pbPrevDevSpecificCfg + uOffset, 1729 RT_MIN(cb, pVirtioCC->cbDevSpecificCfg - uOffset))); 1600 1730 1601 1731 memcpy(pVirtioCC->pbPrevDevSpecificCfg, pVirtioCC->pbDevSpecificCfg, pVirtioCC->cbDevSpecificCfg); … … 1618 1748 } 1619 1749 1620 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocCommonCfgCap))1621 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, false /* fWrite */, offIntra, cb, pv);1622 1623 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))1750 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocCommonCfgCap)) 1751 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, false /* fWrite */, uOffset, cb, pv); 1752 1753 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocIsrCap) && cb == sizeof(uint8_t)) 1624 1754 { 1625 1755 *(uint8_t *)pv = pVirtio->uISR; … … 1650 1780 1651 1781 Assert(pVirtio == (PVIRTIOCORE)pvUser); RT_NOREF(pvUser); 1652 uint32_t offIntra;1653 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocDeviceCap))1782 uint32_t uOffset; 1783 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocDeviceCap)) 1654 1784 { 1655 1785 #ifdef IN_RING3 … … 1657 1787 * Pass this MMIO write access back to the client to handle 1658 1788 */ 1659 return pVirtioCC->pfnDevCapWrite(pDevIns, offIntra, pv, cb);1789 return pVirtioCC->pfnDevCapWrite(pDevIns, uOffset, pv, cb); 1660 1790 #else 1661 1791 return VINF_IOM_R3_MMIO_WRITE; … … 1663 1793 } 1664 1794 1665 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocCommonCfgCap))1666 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, true /* fWrite */, offIntra, cb, (void *)pv);1667 1668 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocIsrCap) && cb == sizeof(uint8_t))1795 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocCommonCfgCap)) 1796 return virtioCommonCfgAccessed(pDevIns, pVirtio, pVirtioCC, true /* fWrite */, uOffset, cb, (void *)pv); 1797 1798 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocIsrCap) && cb == sizeof(uint8_t)) 1669 1799 { 1670 1800 pVirtio->uISR = *(uint8_t *)pv; … … 1677 1807 1678 1808 /* This *should* be guest driver dropping index of a new descriptor in avail ring */ 1679 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, offIntra, pVirtio->LocNotifyCap) && cb == sizeof(uint16_t))1680 { 1681 virtio QueueNotified(pDevIns, pVirtio, offIntra/ VIRTIO_NOTIFY_OFFSET_MULTIPLIER, *(uint16_t *)pv);1809 if (MATCHES_VIRTIO_CAP_STRUCT(off, cb, uOffset, pVirtio->LocNotifyCap) && cb == sizeof(uint16_t)) 1810 { 1811 virtioCoreQueueNotified(pDevIns, pVirtio, uOffset / VIRTIO_NOTIFY_OFFSET_MULTIPLIER, *(uint16_t *)pv); 1682 1812 return VINF_SUCCESS; 1683 1813 } … … 1802 1932 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueEnable[i]); 1803 1933 pHlp->pfnSSMPutU16(pSSM, pVirtio->uQueueSize[i]); 1804 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uAvailIdx );1805 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uUsedIdx );1934 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uAvailIdxShadow); 1935 pHlp->pfnSSMPutU16(pSSM, pVirtio->virtqState[i].uUsedIdxShadow); 1806 1936 int rc = pHlp->pfnSSMPutMem(pSSM, pVirtio->virtqState[i].szVirtqName, 32); 1807 1937 AssertRCReturn(rc, rc); … … 1860 1990 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueEnable[i]); 1861 1991 pHlp->pfnSSMGetU16(pSSM, &pVirtio->uQueueSize[i]); 1862 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uAvailIdx );1863 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uUsedIdx );1992 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uAvailIdxShadow); 1993 pHlp->pfnSSMGetU16(pSSM, &pVirtio->virtqState[i].uUsedIdxShadow); 1864 1994 rc = pHlp->pfnSSMGetMem(pSSM, pVirtio->virtqState[i].szVirtqName, 1865 1995 sizeof(pVirtio->virtqState[i].szVirtqName)); … … 1898 2028 break; 1899 2029 case kvirtIoVmStateChangedResume: 1900 virtio NotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* idxQueue */);2030 virtioCoreNotifyGuestDriver(pVirtio->pDevInsR3, pVirtio, 0 /* idxQueue */); 1901 2031 break; 1902 2032 default: -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r84468 r84774 53 53 */ 54 54 #define VIRTIO_MAX_QUEUE_NAME_SIZE 32 /**< Maximum length of a queue name */ 55 #define VIRTQ_MAX_ SIZE1024 /**< Max size (# desc elements) of a virtq */55 #define VIRTQ_MAX_ENTRIES 1024 /**< Max size (# desc elements) of a virtq */ 56 56 #define VIRTQ_MAX_CNT 24 /**< Max queues we allow guest to create */ 57 57 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ … … 71 71 typedef struct VIRTIOSGSEG /**< An S/G entry */ 72 72 { 73 RTGCPHYS gcPhys; /**< Pointer to the segment buffer */73 RTGCPHYS GCPhys; /**< Pointer to the segment buffer */ 74 74 size_t cbSeg; /**< Size of the segment buffer */ 75 75 } VIRTIOSGSEG; … … 84 84 unsigned cSegs; /**< Number of segments */ 85 85 unsigned idxSeg; /**< Current segment we are in */ 86 /** @todo r=bird: s/gcPhys/GCPhys/g as this is how we write it everywhere. */ 87 RTGCPHYS gcPhysCur; /**< Ptr to byte within the current seg */ 86 RTGCPHYS GCPhysCur; /**< Ptr to byte within the current seg */ 88 87 size_t cbSegLeft; /**< # of bytes left in the current segment */ 89 88 } VIRTIOSGBUF; … … 110 109 VIRTIOSGBUF SgBufIn; 111 110 VIRTIOSGBUF SgBufOut; 112 VIRTIOSGSEG aSegsIn[VIRTQ_MAX_ SIZE];113 VIRTIOSGSEG aSegsOut[VIRTQ_MAX_ SIZE];111 VIRTIOSGSEG aSegsIn[VIRTQ_MAX_ENTRIES]; 112 VIRTIOSGSEG aSegsOut[VIRTQ_MAX_ENTRIES]; 114 113 /** @} */ 115 114 } VIRTIO_DESC_CHAIN_T; … … 188 187 typedef struct VIRTQSTATE 189 188 { 190 char szVirtqName[32]; /**< Dev-specific name of queue */ 191 uint16_t uAvailIdx; /**< Consumer's position in avail ring */ 192 uint16_t uUsedIdx; /**< Consumer's position in used ring */ 193 bool fEventThresholdReached; /**< Don't lose track while queueing ahead */ 189 uint16_t idxQueue; /**< Index of this queue */ 190 char szVirtqName[32]; /**< Dev-specific name of queue */ 191 uint16_t uAvailIdxShadow; /**< Consumer's position in avail ring */ 192 uint16_t uUsedIdxShadow; /**< Consumer's position in used ring */ 193 bool fVirtqRingEventThreshold; /**< Don't lose track while queueing ahead */ 194 194 } VIRTQSTATE, *PVIRTQSTATE; 195 195 … … 274 274 /** @name The locations of the capability structures in PCI config space and the BAR. 275 275 * @{ */ 276 VIRTIO_PCI_CAP_LOCATIONS_T LocPciCfgCap; /**< VIRTIO_PCI_CFG_CAP_T */277 VIRTIO_PCI_CAP_LOCATIONS_T LocNotifyCap; /**< VIRTIO_PCI_NOTIFY_CAP_T */278 VIRTIO_PCI_CAP_LOCATIONS_T LocCommonCfgCap; /**< VIRTIO_PCI_CAP_T */279 VIRTIO_PCI_CAP_LOCATIONS_T LocIsrCap; /**< VIRTIO_PCI_CAP_T */280 VIRTIO_PCI_CAP_LOCATIONS_T LocDeviceCap; /**< VIRTIO_PCI_CAP_T + custom data. */276 VIRTIO_PCI_CAP_LOCATIONS_T LocPciCfgCap; /**< VIRTIO_PCI_CFG_CAP_T */ 277 VIRTIO_PCI_CAP_LOCATIONS_T LocNotifyCap; /**< VIRTIO_PCI_NOTIFY_CAP_T */ 278 VIRTIO_PCI_CAP_LOCATIONS_T LocCommonCfgCap; /**< VIRTIO_PCI_CAP_T */ 279 VIRTIO_PCI_CAP_LOCATIONS_T LocIsrCap; /**< VIRTIO_PCI_CAP_T */ 280 VIRTIO_PCI_CAP_LOCATIONS_T LocDeviceCap; /**< VIRTIO_PCI_CAP_T + custom data. */ 281 281 /** @} */ 282 282 283 bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */284 uint8_t uPciCfgDataOff; 285 uint8_t uISR; /**< Interrupt Status Register. */286 uint8_t fMsiSupport; 283 bool fGenUpdatePending; /**< If set, update cfg gen after driver reads */ 284 uint8_t uPciCfgDataOff; /**< Offset to PCI configuration data area */ 285 uint8_t uISR; /**< Interrupt Status Register. */ 286 uint8_t fMsiSupport; /**< Flag set if using MSI instead of ISR */ 287 287 288 288 /** The MMIO handle for the PCI capability region (\#2). */ … … 405 405 * @{ */ 406 406 407 int virtioCoreR3QueueAttach(PVIRTIOCORE pVirtio, uint16_t idxQueue, const char *pcszName); 408 409 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 410 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain); 407 int virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 408 uint16_t virtioCoreQueueAvailCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 409 void virtioCoreQueueEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnable); 410 void virtioCoreQueueNotifyEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnable); 411 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio); 412 void virtioCoreResetAll(PVIRTIOCORE pVirtio); 413 void virtioCorePrintFeatures(VIRTIOCORE *pVirtio, PCDBGFINFOHLP pHlp); 414 411 415 uint32_t virtioCoreR3DescChainRetain(PVIRTIO_DESC_CHAIN_T pDescChain); 412 416 uint32_t virtioCoreR3DescChainRelease(PVIRTIOCORE pVirtio, PVIRTIO_DESC_CHAIN_T pDescChain); 413 414 int virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 415 PPVIRTIO_DESC_CHAIN_T ppDescChain); 416 417 int virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue); 418 419 int virtioCoreR3QueueGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 420 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 421 422 int virtioCoreR3QueuePut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn, 423 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 424 425 int virtioCoreR3QueuePendingCount(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 426 int virtioCoreQueueSync(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 427 bool virtioCoreQueueIsEmpty(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue); 428 void virtioCoreQueueEnable(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled); 429 void virtioCoreQueueSetNotify(PVIRTIOCORE pVirtio, uint16_t idxQueue, bool fEnabled); 430 void virtioCoreNotifyConfigChanged(PVIRTIOCORE pVirtio); 431 void virtioCoreResetAll(PVIRTIOCORE pVirtio); 432 void virtioPrintFeatures(VIRTIOCORE *pVirtio); 417 void virtioCoreR3Info(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs); 418 void virtioCoreR3QueueInfo(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs, int idxQueue); 419 int virtioCoreR3QueueAttach(PVIRTIOCORE pVirtio, uint16_t idxQueue, const char *pcszName); 420 421 int virtioCoreR3DescChainGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 422 uint16_t uHeadIdx, PPVIRTIO_DESC_CHAIN_T ppDescChain); 423 424 int virtioCoreR3QueuePeek(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 425 PPVIRTIO_DESC_CHAIN_T ppDescChain); 426 427 int virtioCoreR3QueueSkip(PVIRTIOCORE pVirtio, uint16_t idxQueue); 428 429 int virtioCoreR3QueueGet(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, 430 PPVIRTIO_DESC_CHAIN_T ppDescChain, bool fRemove); 431 432 int virtioCoreR3QueuePut(PPDMDEVINS pDevIns, PVIRTIOCORE pVirtio, uint16_t idxQueue, PRTSGBUF pSgVirtReturn, 433 PVIRTIO_DESC_CHAIN_T pDescChain, bool fFence); 434 433 435 434 436 /** … … 437 439 * @param pVirtio Pointer to the virtio state. 438 440 * @param idxQueue Queue number. 439 * @ param fEnabled Flagindicating whether to enable queue or not441 * @returns true or false indicating whether to enable queue or not 440 442 */ 441 443 DECLINLINE(bool) virtioCoreIsQueueEnabled(PVIRTIOCORE pVirtio, uint16_t idxQueue) … … 500 502 int fWrite, int fHasIndex, uint32_t idx); 501 503 504 /* Debug assist functions for consumer device code */ 502 505 void virtioCoreHexDump(uint8_t *pv, uint32_t cb, uint32_t uBase, const char *pszTitle); 503 void virtioCoreGcPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS gcPhys, uint32_t cb, uint32_t uBase, const char *pszTitle); 506 void virtioCoreGCPhysHexDump(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint16_t cb, uint32_t uBase, const char *pszTitle); 507 504 508 505 509 void virtioCoreSgBufInit(PVIRTIOSGBUF pGcSgBuf, PVIRTIOSGSEG paSegs, size_t cSegs); … … 511 515 void virtioCoreSgBufReset(PVIRTIOSGBUF pGcSgBuf); 512 516 size_t virtioCoreSgBufCalcTotalLength(PVIRTIOSGBUF pGcSgBuf); 517 513 518 int virtioCoreR3SaveExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM); 514 519 int virtioCoreR3LoadExec(PVIRTIOCORE pVirtio, PCPDMDEVHLPR3 pHlp, PSSMHANDLE pSSM);
Note:
See TracChangeset
for help on using the changeset viewer.

