Changeset 85415 in vbox for trunk/src/VBox/Devices/Network
- Timestamp:
- Jul 22, 2020 2:44:19 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Network/DevVirtioNet_1_0.cpp
r85291 r85415 60 60 61 61 #define LUN0 0 62 63 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1)64 #define VIRTIONET_MAX_QPAIRS 165 #define VIRTIONET_MAX_VIRTQS (VIRTIONET_MAX_QPAIRS * 2 + 1)66 #define VIRTIONET_MAX_FRAME_SIZE 65535 + 18 /**< Max IP pkt size + Eth. header w/VLAN tag */67 #define VIRTIONET_MAC_FILTER_LEN 3268 #define VIRTIONET_MAX_VLAN_ID (1 << 12)69 #define VIRTIONET_RX_SEG_COUNT 3270 71 #define VIRTQNAME(uVirtqNbr) (pThis->aVirtqs[uVirtqNbr]->szName)72 #define CBVIRTQNAME(uVirtqNbr) RTStrNLen(VIRTQNAME(uVirtqNbr), sizeof(VIRTQNAME(uVirtqNbr)))73 #define FEATURE_ENABLED(feature) RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature)74 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature))75 #define FEATURE_OFFERED(feature) VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature76 77 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */78 #define IS_TX_VIRTQ(n) ((n) != CTRLQIDX && ((n) & 1))79 #define IS_RX_VIRTQ(n) ((n) != CTRLQIDX && !IS_TX_VIRTQ(n))80 #define IS_CTRL_VIRTQ(n) ((n) == CTRLQIDX)81 #define RXQIDX(qPairIdx) (qPairIdx * 2)82 #define TXQIDX(qPairIdx) (qPairIdx * 2 + 1)83 #define CTRLQIDX (FEATURE_ENABLED(MQ) ? ((VIRTIONET_MAX_QPAIRS - 1) * 2 + 2) : 2)84 85 #define IS_LINK_UP(pState) (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP)86 #define IS_LINK_DOWN(pState) !IS_LINK_UP(pState)87 88 \89 #define SET_LINK_UP(pState) \90 LogFunc(("SET_LINK_UP\n")); \91 pState->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; \92 virtioCoreNotifyConfigChanged(&pThis->Virtio)93 94 #define SET_LINK_DOWN(pState) \95 LogFunc(("SET_LINK_DOWN\n")); \96 pState->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP; \97 virtioCoreNotifyConfigChanged(&pThis->Virtio)98 99 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, uVirtqNbr) \100 (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0)101 102 103 #ifdef USING_CRITICAL_SECTION104 # define ENTER_CRITICAL_SECTION \105 do { \106 int rc = virtioNetR3CsEnter(pDevIns, pThis, VERR_SEM_BUSY); \107 AssertRCReturnVoid(rc); \108 RT_NOREF(rc);109 } while(0)110 # define LEAVE_CRITICAL_SECTION \111 do { \112 virtioNetR3CsLeave(pDevIns, pThis); \113 } while(0)114 #else115 # define ENTER_CRITICAL_SECTION do { } while(0)116 # define LEAVE_CRITICAL_SECTION do { } while(0)117 #endif118 119 /*120 * Glossary of networking acronyms used in the following bit definitions:121 *122 * GSO = Generic Segmentation Offload123 * TSO = TCP Segmentation Offload124 * UFO = UDP Fragmentation Offload125 * ECN = Explicit Congestion Notification126 */127 62 128 63 /** @name VirtIO 1.0 NET Host feature bits (See VirtIO 1.0 specification, Section 5.6.3) … … 175 110 | VIRTIONET_F_MRG_RXBUF 176 111 112 /* 113 * Glossary of networking acronyms used in the previous bit definitions: 114 * 115 * GSO = Generic Segmentation Offload 116 * TSO = TCP Segmentation Offload 117 * UFO = UDP Fragmentation Offload 118 * ECN = Explicit Congestion Notification 119 */ 120 121 #define FEATURE_ENABLED(feature) RT_BOOL(pThis->fNegotiatedFeatures & VIRTIONET_F_##feature) 122 #define FEATURE_DISABLED(feature) (!FEATURE_ENABLED(feature)) 123 #define FEATURE_OFFERED(feature) VIRTIONET_HOST_FEATURES_OFFERED & VIRTIONET_F_##feature 124 125 #define VIRTIONET_SAVED_STATE_VERSION UINT32_C(1) 126 127 #if FEATURE_OFFERED(MQ) 128 # define VIRTIONET_MAX_QPAIRS 1000 129 #else 130 # define VIRTIONET_MAX_QPAIRS VIRTIONET_CTRL_MQ_VQ_PAIRS_MIN 131 #endif 132 133 #define VIRTIONET_MAX_VIRTQS (VIRTIONET_MAX_QPAIRS * 2 + 1) 134 #define VIRTIONET_MAX_FRAME_SIZE 65535 + 18 /**< Max IP pkt size + Eth. header w/VLAN tag */ 135 #define VIRTIONET_MAC_FILTER_LEN 32 136 #define VIRTIONET_MAX_VLAN_ID (1 << 12) 137 #define VIRTIONET_RX_SEG_COUNT 32 138 139 #define VIRTQNAME(uVirtqNbr) (pThis->aVirtqs[uVirtqNbr]->szName) 140 #define CBVIRTQNAME(uVirtqNbr) RTStrNLen(VIRTQNAME(uVirtqNbr), sizeof(VIRTQNAME(uVirtqNbr))) 141 142 /* Macros to calculate queue specific index number VirtIO 1.0, 5.1.2 */ 143 #define IS_TX_VIRTQ(n) ((n) != CTRLQIDX && ((n) & 1)) 144 #define IS_RX_VIRTQ(n) ((n) != CTRLQIDX && !IS_TX_VIRTQ(n)) 145 #define IS_CTRL_VIRTQ(n) ((n) == CTRLQIDX) 146 #define RXQIDX(qPairIdx) (qPairIdx * 2) 147 #define TXQIDX(qPairIdx) (RXQIDX(qPairIdx) + 1) 148 #define CTRLQIDX (FEATURE_ENABLED(MQ) ? ((VIRTIONET_MAX_QPAIRS - 1) * 2 + 2) : 2) 149 150 #define IS_LINK_UP(pState) (pState->virtioNetConfig.uStatus & VIRTIONET_F_LINK_UP) 151 #define IS_LINK_DOWN(pState) !IS_LINK_UP(pState) 152 153 #define SET_LINK_UP(pState) \ 154 LogFunc(("SET_LINK_UP\n")); \ 155 pState->virtioNetConfig.uStatus |= VIRTIONET_F_LINK_UP; \ 156 virtioCoreNotifyConfigChanged(&pThis->Virtio) 157 158 #define SET_LINK_DOWN(pState) \ 159 LogFunc(("SET_LINK_DOWN\n")); \ 160 pState->virtioNetConfig.uStatus &= ~VIRTIONET_F_LINK_UP; \ 161 virtioCoreNotifyConfigChanged(&pThis->Virtio) 162 163 #define IS_VIRTQ_EMPTY(pDevIns, pVirtio, uVirtqNbr) \ 164 (virtioCoreVirtqAvailBufCount(pDevIns, pVirtio, uVirtqNbr) == 0) 165 177 166 #define PCI_DEVICE_ID_VIRTIONET_HOST 0x1041 /**< Informs guest driver of type of VirtIO device */ 178 167 #define PCI_CLASS_BASE_NETWORK_CONTROLLER 0x02 /**< PCI Network device class */ … … 303 292 /** @name Control virtq: Setting Offloads State (VirtIO 1.0, 5.1.6.5.6.1) 304 293 * @{ */ 305 #define VIRTIO _NET_CTRL_GUEST_OFFLOADS 5 /**< Control class: Offloads state configuration */306 #define VIRTIO _NET_CTRL_GUEST_OFFLOADS_SET 0 /** Apply new offloads configuration */294 #define VIRTIONET_CTRL_GUEST_OFFLOADS 5 /**< Control class: Offloads state configuration */ 295 #define VIRTIONET_CTRL_GUEST_OFFLOADS_SET 0 /** Apply new offloads configuration */ 307 296 /** @} */ 308 297 … … 317 306 struct VIRTIONETWORKER *pWorker; /**< Pointer to R0 worker struct */ 318 307 struct VIRTIONETWORKERR3 *pWorkerR3; /**< Pointer to R3 worker struct */ 319 uint16_t idx;/**< Index of this queue */308 uint16_t uIdx; /**< Index of this queue */ 320 309 uint16_t align; 321 310 char szName[VIRTIO_MAX_VIRTQ_NAME_SIZE]; /**< Virtq name */ … … 333 322 SUPSEMEVENT hEvtProcess; /**< handle of associated sleep/wake-up semaphore */ 334 323 PVIRTIONETVIRTQ pVirtq; /**< pointer to queue */ 335 uint16_t idx;/**< Index of this worker */324 uint16_t uIdx; /**< Index of this worker */ 336 325 bool volatile fSleeping; /**< Flags whether worker thread is sleeping or not */ 337 326 bool volatile fNotified; /**< Flags whether worker thread notified */ … … 349 338 R3PTRTYPE(PPDMTHREAD) pThread; /**< pointer to worker thread's handle */ 350 339 PVIRTIONETVIRTQ pVirtq; /**< pointer to queue */ 351 uint16_t idx;/**< Index of this worker */340 uint16_t uIdx; /**< Index of this worker */ 352 341 uint16_t pad; 353 342 } VIRTIONETWORKERR3; … … 383 372 uint16_t cVirtqPairs; 384 373 374 /** Number of Rx/Tx queue pairs that have already been initialized */ 375 uint16_t cInitializedVirtqPairs; 376 385 377 /** Number of virtqueues total (which includes each queue of each pair plus one control queue */ 386 378 uint16_t cVirtVirtqs; … … 433 425 /** Resetting flag */ 434 426 uint8_t fResetting; 435 436 /** Quiescing I/O activity flag */437 uint8_t fQuiescing;438 427 439 428 /** Promiscuous mode -- RX filter accepts all packets. */ … … 525 514 TMTIMERHANDLE hLinkUpTimer; 526 515 527 /** True if in the process of quiescing I/O */528 uint32_t fQuiescing;529 530 /** For which purpose we're quiescing. */531 VIRTIOVMSTATECHANGED enmQuiescingFor;532 533 516 } VIRTIONETR3; 534 517 … … 571 554 #ifdef IN_RING3 572 555 static DECLCALLBACK(int) virtioNetR3WorkerThread(PPDMDEVINS pDevIns, PPDMTHREAD pThread); 556 static int virtioNetR3CreateWorkerThreads(PPDMDEVINS, PVIRTIONET, PVIRTIONETCC); 573 557 574 558 DECLINLINE(const char *) virtioNetThreadStateName(PPDMTHREAD pThread) … … 693 677 { 694 678 RTStrCopy(pThis->aVirtqs[CTRLQIDX].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "controlq"); 695 for (uint16_t qPairIdx = 0; qPairIdx < pThis->cVirtqPairs; qPairIdx++)679 for (uint16_t qPairIdx = pThis->cInitializedVirtqPairs; qPairIdx < pThis->cVirtqPairs; qPairIdx++) 696 680 { 697 681 RTStrPrintf(pThis->aVirtqs[RXQIDX(qPairIdx)].szName, VIRTIO_MAX_VIRTQ_NAME_SIZE, "receiveq<%d>", qPairIdx); … … 854 838 if (pVirtq->fHasWorker) 855 839 { 856 PVIRTIONETWORKER pWorker= pVirtq->pWorker;840 PVIRTIONETWORKER pWorker = pVirtq->pWorker; 857 841 PVIRTIONETWORKERR3 pWorkerR3 = pVirtq->pWorkerR3; 858 842 … … 910 894 911 895 pHlp->pfnPrintf(pHlp, " Transmitting: ............. %s\n", fTransmitting ? "true" : "false"); 912 pHlp->pfnPrintf(pHlp, " Quiescing: ................ %s %s%s%s\n",913 pThis->fQuiescing ? "true" : "false",914 pThis->fQuiescing ? "(" : "",915 pThis->fQuiescing ? virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor) : "",916 pThis->fQuiescing ? ")" : "");917 pHlp->pfnPrintf(pHlp, " Resetting: ................ %s\n", pThis->fResetting ? "true" : "false");918 896 pHlp->pfnPrintf(pHlp, "\n"); 919 897 pHlp->pfnPrintf(pHlp, "Misc state\n"); … … 1153 1131 * Nudge queue workers 1154 1132 */ 1155 for (int idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++)1156 { 1157 PVIRTIONETWORKER pWorker = &pThis->aWorkers[ idxWorker];1133 for (int uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++) 1134 { 1135 PVIRTIONETWORKER pWorker = &pThis->aWorkers[uIdxWorker]; 1158 1136 PVIRTIONETVIRTQ pVirtq = pWorker->pVirtq; 1159 1137 if (pVirtq->fAttachedToVirtioCore) … … 1224 1202 * Device interface. * 1225 1203 *********************************************************************************************************************************/ 1226 /*xx*/1227 /**1228 * @callback_method_impl{FNPDMDEVASYNCNOTIFY}1229 */1230 static DECLCALLBACK(bool) virtioNetR3DeviceQuiesced(PPDMDEVINS pDevIns)1231 {1232 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1233 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);1234 1235 /** @todo create test to conclusively determine I/O has been quiesced and add it here: */1236 1237 Log7Func(("%s Device I/O activity quiesced: %s\n",1238 pThis->szInst, virtioCoreGetStateChangeText(pThisCC->enmQuiescingFor)));1239 1240 virtioCoreR3VmStateChanged(&pThis->Virtio, pThisCC->enmQuiescingFor);1241 1242 pThis->fResetting = false;1243 pThisCC->fQuiescing = false;1244 1245 return true;1246 }1247 1248 /**1249 * Worker for virtioNetR3Reset() and virtioNetR3SuspendOrPowerOff().1250 */1251 static void virtioNetR3QuiesceDevice(PPDMDEVINS pDevIns, VIRTIOVMSTATECHANGED enmQuiescingFor)1252 {1253 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1254 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);1255 1256 RT_NOREF(pThis);1257 1258 /* Prevent worker threads from removing/processing elements from virtq's */1259 pThisCC->fQuiescing = true;1260 pThisCC->enmQuiescingFor = enmQuiescingFor;1261 1262 /*1263 * Wake downstream network driver thread that's waiting for Rx buffers to be available1264 * to tell it that's going to happen...1265 */1266 virtioNetWakeupRxBufWaiter(pDevIns);1267 1268 PDMDevHlpSetAsyncNotification(pDevIns, virtioNetR3DeviceQuiesced);1269 1270 /* If already quiesced invoke async callback. */1271 if (!ASMAtomicReadBool(&pThis->fLeafWantsEmptyRxBufs))1272 PDMDevHlpAsyncNotificationCompleted(pDevIns);1273 1274 /** @todo make sure Rx and Tx are really quiesced (how do we synchronize w/downstream driver?) */1275 }1276 1277 /**1278 * @interface_method_impl{PDMDEVREGR3,pfnReset}1279 */1280 static DECLCALLBACK(void) virtioNetR3Reset(PPDMDEVINS pDevIns)1281 {1282 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1283 Log7Func(("%s\n", pThis->szInst));1284 pThis->fResetting = true;1285 virtioNetR3QuiesceDevice(pDevIns, kvirtIoVmStateChangedReset);1286 }1287 1288 /**1289 * @interface_method_impl{PDMDEVREGR3,pfnPowerOff}1290 */1291 static DECLCALLBACK(void) virtioNetR3SuspendOrPowerOff(PPDMDEVINS pDevIns, VIRTIOVMSTATECHANGED enmType)1292 {1293 1294 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1295 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);1296 Log7Func(("%s\n", pThis->szInst));1297 1298 RT_NOREF2(pThis, pThisCC);1299 1300 virtioNetR3QuiesceDevice(pDevIns, enmType);1301 virtioNetWakeupRxBufWaiter(pDevIns);1302 }1303 1304 /**1305 * @interface_method_impl{PDMDEVREGR3,pfnSuspend}1306 */1307 static DECLCALLBACK(void) virtioNetR3PowerOff(PPDMDEVINS pDevIns)1308 {1309 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1310 Log7Func(("%s\n", pThis->szInst));1311 RT_NOREF(pThis);1312 virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedPowerOff);1313 }1314 1315 /**1316 * @interface_method_impl{PDMDEVREGR3,pfnSuspend}1317 */1318 static DECLCALLBACK(void) virtioNetR3Suspend(PPDMDEVINS pDevIns)1319 {1320 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1321 Log7Func(("%s \n", pThis->szInst));1322 RT_NOREF(pThis);1323 virtioNetR3SuspendOrPowerOff(pDevIns, kvirtIoVmStateChangedSuspend);1324 }1325 1326 /**1327 * @interface_method_impl{PDMDEVREGR3,pfnResume}1328 *1329 * Just process the VM device-related state change itself.1330 * Unlike SCSI driver, there are no packets to redo. No I/O was halted or saved while1331 * quiescing for pfnSuspend(). Any packets in process were simply dropped by the upper1332 * layer driver, presumably to be retried or cause erring out at the upper layers1333 * of the network stack.1334 */1335 static DECLCALLBACK(void) virtioNetR3Resume(PPDMDEVINS pDevIns)1336 {1337 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET);1338 PVIRTIONETCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PVIRTIONETCC);1339 Log7Func(("\n"));1340 1341 pThisCC->fQuiescing = false;1342 1343 /* Ensure guest is working the queues */1344 virtioCoreR3VmStateChanged(&pThis->Virtio, kvirtIoVmStateChangedResume);1345 }1346 1204 1347 1205 #ifdef IN_RING3 … … 1407 1265 DECLINLINE(bool) virtioNetIsOperational(PVIRTIONET pThis, PPDMDEVINS pDevIns) 1408 1266 { 1409 if (RT_LIKELY(pThis->fVirtioReady) && RT_LIKELY(!pThis->fQuiescing))1267 if (RT_LIKELY(pThis->fVirtioReady)) 1410 1268 { 1411 1269 VMSTATE enmVMState = PDMDevHlpVMState(pDevIns); … … 1434 1292 Log8Func(("%s No Rx bufs available. (VirtIO core not ready)\n", pThis->szInst)); 1435 1293 1436 else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq-> idx))1294 else if (!virtioCoreIsVirtqEnabled(&pThis->Virtio, pRxVirtq->uIdx)) 1437 1295 Log8Func(("%s No Rx bufs available. (%s not enabled)\n", pThis->szInst, pRxVirtq->szName)); 1438 1296 1439 else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq-> idx))1297 else if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pRxVirtq->uIdx)) 1440 1298 Log8Func(("%s No Rx bufs available. (%s empty)\n", pThis->szInst, pRxVirtq->szName)); 1441 1299 … … 1445 1303 rc = VINF_SUCCESS; 1446 1304 } 1447 virtioCoreVirtqEnableNotify(&pThis->Virtio, pRxVirtq-> idx, rc == VERR_INVALID_STATE /* fEnable */);1305 virtioCoreVirtqEnableNotify(&pThis->Virtio, pRxVirtq->uIdx, rc == VERR_INVALID_STATE /* fEnable */); 1448 1306 return rc; 1449 1307 } … … 1473 1331 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1474 1332 1333 if (!virtioNetIsOperational(pThis, pDevIns)) 1334 return VERR_INTERRUPTED; 1335 1475 1336 if (virtioNetR3RxBufsAvail(pDevIns, pThis, NULL /* pRxVirtq */)) 1476 1337 { … … 1482 1343 1483 1344 LogFunc(("%s %s\n", pThis->szInst, timeoutMs == RT_INDEFINITE_WAIT ? "<indefinite wait>" : "")); 1345 1484 1346 1485 1347 ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, true); … … 1490 1352 { 1491 1353 Log10Func(("%s Rx bufs now available, releasing waiter...\n", pThis->szInst)); 1354 ASMAtomicXchgBool(&pThis->fLeafWantsEmptyRxBufs, false); 1492 1355 return VINF_SUCCESS; 1493 1356 } … … 1499 1362 { 1500 1363 LogFunc(("Woken due to %s\n", rc == VERR_TIMEOUT ? "timeout" : "getting interrupted")); 1364 1365 if (!virtioNetIsOperational(pThis, pDevIns)) 1366 break; 1367 1501 1368 continue; 1502 1369 } … … 1697 1564 PVIRTQBUF pVirtqBuf = NULL; 1698 1565 1699 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq-> idx, &pVirtqBuf, true);1566 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, &pVirtqBuf, true); 1700 1567 AssertMsgReturn(rc == VINF_SUCCESS || rc == VERR_NOT_AVAILABLE, ("%Rrc\n", rc), rc); 1701 1568 … … 1733 1600 /* Calculate & cache GCPhys addr of field to update after final value is known */ 1734 1601 GCPhysPktHdrNumBuffers = pVirtqBuf->pSgPhysReturn->paSegs[0].GCPhys 1735 1602 + RT_UOFFSETOF(VIRTIONETPKTHDR, uNumBuffers); 1736 1603 fAddPktHdr = false; 1737 1604 cSegs++; … … 1758 1625 Log7Func(("Send Rx pkt to guest...\n")); 1759 1626 STAM_PROFILE_START(&pThis->StatReceiveStore, a); 1760 virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq-> idx,1627 virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, pRxVirtq->uIdx, 1761 1628 pVirtSegBufToGuest, pVirtqBuf, true /* fFence */); 1762 1629 STAM_PROFILE_STOP(&pThis->StatReceiveStore, a); … … 1779 1646 AssertMsgRCReturn(rc, ("Failure updating descriptor count in pkt hdr in guest physical memory\n"), rc); 1780 1647 1781 virtioCoreVirtq SyncUsedRing(pDevIns, &pThis->Virtio, pRxVirtq->idx);1648 virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, pRxVirtq->uIdx); 1782 1649 1783 1650 return VINF_SUCCESS; … … 1797 1664 * @param cb Number of bytes available in the buffer. 1798 1665 * @param pGso Pointer to Global Segmentation Offload structure 1799 * @param idxRxVirtq Rx queue to work with1666 * @param pRxVirtq Pointer to Rx virtqueue 1800 1667 * @thread RX 1801 1668 */ … … 1876 1743 PPDMDEVINS pDevIns = pThisCC->pDevIns; 1877 1744 PVIRTIONET pThis = PDMDEVINS_2_DATA(pDevIns, PVIRTIONET); 1745 1878 1746 if (!pThis->fVirtioReady) 1879 1747 { 1880 1748 LogRelFunc(("VirtIO not ready, aborting downstream receive\n")); 1881 return VERR_INTERRUPTED;1882 }1883 if (pThis->fQuiescing)1884 {1885 LogRelFunc(("Quiescing I/O for suspend or power off, aborting downstream receive\n"));1886 1749 return VERR_INTERRUPTED; 1887 1750 } … … 2102 1965 LogFunc((" %RTmac\n", &pThis->aMacMulticastFilter[i])); 2103 1966 #endif 1967 break; 1968 } 1969 default: 1970 LogRelFunc(("Unrecognized MAC subcommand in CTRL pkt from guest\n")); 1971 return VIRTIONET_ERROR; 1972 } 1973 return VIRTIONET_OK; 1974 } 1975 1976 static uint8_t virtioNetR3CtrlMultiQueue(PVIRTIONET pThis, PVIRTIONETCC pThisCC, PPDMDEVINS pDevIns, PVIRTIONET_CTRL_HDR_T pCtrlPktHdr, PVIRTQBUF pVirtqBuf) 1977 { 1978 LogFunc(("%s Processing CTRL MQ command\n", pThis->szInst)); 1979 1980 uint16_t cVirtqPairs; 1981 switch(pCtrlPktHdr->uCmd) 1982 { 1983 case VIRTIONET_CTRL_MQ_VQ_PAIRS_SET: 1984 { 1985 size_t cbRemaining = pVirtqBuf->cbPhysSend - sizeof(*pCtrlPktHdr); 1986 1987 AssertMsgReturn(cbRemaining > sizeof(cVirtqPairs), 1988 ("DESC chain too small for VIRTIONET_CTRL_MQ cmd processing"), VIRTIONET_ERROR); 1989 1990 /* Fetch number of virtq pairs from guest buffer */ 1991 virtioCoreR3VirtqBufDrain(&pThis->Virtio, pVirtqBuf, &cVirtqPairs, sizeof(cVirtqPairs)); 1992 1993 AssertMsgReturn(cVirtqPairs > VIRTIONET_MAX_QPAIRS, 1994 ("%s Guest CTRL MQ virtq pair count out of range)\n", pThis->szInst, cVirtqPairs), VIRTIONET_ERROR); 1995 1996 LogFunc(("%s Guest specifies %d VQ pairs in use\n", pThis->szInst, cVirtqPairs)); 1997 pThis->cVirtqPairs = cVirtqPairs; 1998 break; 1999 } 2000 default: 2001 LogRelFunc(("Unrecognized multiqueue subcommand in CTRL pkt from guest\n")); 2002 return VIRTIONET_ERROR; 2003 } 2004 2005 /* 2006 * The MQ control function is invoked by the guest in an RPC like manner to change 2007 * the Rx/Tx queue pair count. If the new value exceeds the number of queues 2008 * (and associated workers) already initialized initialize only the new queues and 2009 * respective workers. 2010 */ 2011 if (pThis->cVirtqPairs > pThis->cInitializedVirtqPairs) 2012 { 2013 virtioNetR3SetVirtqNames(pThis); 2014 int rc = virtioNetR3CreateWorkerThreads(pDevIns, pThis, pThisCC); 2015 if (RT_FAILURE(rc)) 2016 { 2017 LogRelFunc(("Failed to create worker threads\n")); 2018 return VIRTIONET_ERROR; 2104 2019 } 2105 2020 } … … 2115 2030 2116 2031 AssertMsgReturn(cbRemaining > sizeof(uVlanId), 2117 ("DESC chain too small for VIRTIO _NET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR);2032 ("DESC chain too small for VIRTIONET_CTRL_VLAN cmd processing"), VIRTIONET_ERROR); 2118 2033 2119 2034 /* Fetch VLAN ID from guest buffer */ … … 2134 2049 break; 2135 2050 default: 2051 LogRelFunc(("Unrecognized VLAN subcommand in CTRL pkt from guest\n")); 2136 2052 return VIRTIONET_ERROR; 2137 2053 } … … 2181 2097 case VIRTIONET_CTRL_VLAN: 2182 2098 uAck = virtioNetR3CtrlVlan(pThis, pCtrlPktHdr, pVirtqBuf); 2099 break; 2100 case VIRTIONET_CTRL_MQ: 2101 uAck = virtioNetR3CtrlMultiQueue(pThis, pThisCC, pDevIns, pCtrlPktHdr, pVirtqBuf); 2183 2102 break; 2184 2103 case VIRTIONET_CTRL_ANNOUNCE: … … 2198 2117 Log7Func(("%s Clearing VIRTIONET_F_ANNOUNCE in config status\n", pThis->szInst)); 2199 2118 break; 2200 2201 2119 default: 2202 2120 LogRelFunc(("Unrecognized CTRL pkt hdr class (%d)\n", pCtrlPktHdr->uClass)); … … 2230 2148 2231 2149 virtioCoreR3VirtqUsedBufPut(pDevIns, &pThis->Virtio, CTRLQIDX, pReturnSegBuf, pVirtqBuf, true /* fFence */); 2232 virtioCoreVirtq SyncUsedRing(pDevIns, &pThis->Virtio, CTRLQIDX);2150 virtioCoreVirtqUsedRingSync(pDevIns, &pThis->Virtio, CTRLQIDX); 2233 2151 2234 2152 for (int i = 0; i < cSegs; i++) … … 2383 2301 } 2384 2302 2385 int cPkts = virtioCoreVirtqAvailBufCount(pVirtio->pDevInsR3, pVirtio, pTxVirtq-> idx);2303 int cPkts = virtioCoreVirtqAvailBufCount(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx); 2386 2304 if (!cPkts) 2387 2305 { … … 2400 2318 int rc; 2401 2319 PVIRTQBUF pVirtqBuf = NULL; 2402 while ((rc = virtioCoreR3VirtqAvailBufPeek(pVirtio->pDevInsR3, pVirtio, pTxVirtq-> idx, &pVirtqBuf)) == VINF_SUCCESS)2320 while ((rc = virtioCoreR3VirtqAvailBufPeek(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, &pVirtqBuf)) == VINF_SUCCESS) 2403 2321 { 2404 2322 Log10Func(("%s fetched descriptor chain from %s\n", pThis->szInst, pTxVirtq->szName)); … … 2485 2403 } 2486 2404 2487 /* Point to next descriptor in avail ring of virtq */2488 virtioCoreR3VirtqAvailBufNext(pVirtio, pTxVirtq-> idx);2405 /* Point to next descriptor chain in avail ring of virtq */ 2406 virtioCoreR3VirtqAvailBufNext(pVirtio, pTxVirtq->uIdx); 2489 2407 2490 2408 /* No data to return to guest, but necessary to put elem (e.g. desc chain head idx) on used ring */ 2491 virtioCoreR3VirtqUsedBufPut(pVirtio->pDevInsR3, pVirtio, pTxVirtq-> idx, NULL, pVirtqBuf, true /* fFence */);2409 virtioCoreR3VirtqUsedBufPut(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx, NULL, pVirtqBuf, true /* fFence */); 2492 2410 2493 2411 /* Update used ring idx and notify guest that we've transmitted the data it sent */ 2494 virtioCoreVirtq SyncUsedRing(pVirtio->pDevInsR3, pVirtio, pTxVirtq->idx);2412 virtioCoreVirtqUsedRingSync(pVirtio->pDevInsR3, pVirtio, pTxVirtq->uIdx); 2495 2413 } 2496 2414 … … 2518 2436 STAM_COUNTER_INC(&pThis->StatTransmitByNetwork); 2519 2437 2520 /** @todo If we ever start using more than one Rx/Tx queue pair, is a random queue2521 selection algorithm feasible or even necessary */2522 2438 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pTxVirtq, true /*fOnWorkerThread*/); 2523 2439 } 2524 2525 2526 #ifdef USING_CRITICAL_SECTION2527 DECLINLINE(int) virtioNetR3CsEnter(PPDMDEVINS pDevIns, PVIRTIONET pThis, int rcBusy)2528 {2529 RT_NOREF(pDevIns, pThis, rcBusy);2530 /* Original DevVirtioNet uses CS in attach/detach/link-up timer/tx timer/transmit */2531 LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", pThis->szInst));2532 return VINF_SUCCESS;2533 }2534 2535 DECLINLINE(void) virtioNetR3CsLeave(PPDMDEVINS pDevIns, PVIRTIONET pThis)2536 {2537 RT_NOREF(pDevIns, pThis);2538 LogFunc(("%s CS unimplemented. What does the critical section protect in orig driver??", pThis->szInst));2539 }2540 #endif /* USING_CRITICAL_SECTION */2541 2440 2542 2441 /** … … 2549 2448 RT_NOREF(pTimer, pvUser); 2550 2449 2551 ENTER_CRITICAL_SECTION;2552 2553 2450 SET_LINK_UP(pThis); 2554 2451 2555 2452 virtioNetWakeupRxBufWaiter(pDevIns); 2556 2557 LEAVE_CRITICAL_SECTION;2558 2453 2559 2454 LogFunc(("%s Link is up\n", pThis->szInst)); … … 2672 2567 Log10Func(("%s\n", pThis->szInst)); 2673 2568 int rc = VINF_SUCCESS; 2674 for (unsigned idxWorker = 0; idxWorker < pThis->cWorkers; idxWorker++)2675 { 2676 PVIRTIONETWORKER pWorker = &pThis->aWorkers[ idxWorker];2677 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[ idxWorker];2569 for (unsigned uIdxWorker = 0; uIdxWorker < pThis->cWorkers; uIdxWorker++) 2570 { 2571 PVIRTIONETWORKER pWorker = &pThis->aWorkers[uIdxWorker]; 2572 PVIRTIONETWORKERR3 pWorkerR3 = &pThisCC->aWorkers[uIdxWorker]; 2678 2573 2679 2574 if (pWorker->hEvtProcess != NIL_SUPSEMEVENT) … … 2694 2589 } 2695 2590 2696 static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint16_t idxWorker,2591 static int virtioNetR3CreateOneWorkerThread(PPDMDEVINS pDevIns, PVIRTIONET pThis, uint16_t uIdxWorker, 2697 2592 PVIRTIONETWORKER pWorker, PVIRTIONETWORKERR3 pWorkerR3, 2698 2593 PVIRTIONETVIRTQ pVirtq) … … 2714 2609 if (RT_FAILURE(rc)) 2715 2610 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, 2716 N_("Error creating thread for Virtual Virtq %s\n"), pVirtq-> idx);2611 N_("Error creating thread for Virtual Virtq %s\n"), pVirtq->uIdx); 2717 2612 2718 2613 pWorker->pVirtq = pWorkerR3->pVirtq = pVirtq; 2719 pWorker-> idx = pWorkerR3->idx = idxWorker;2614 pWorker->uIdx = pWorkerR3->uIdx = uIdxWorker; 2720 2615 pVirtq->pWorker = pWorker; 2721 2616 pVirtq->pWorkerR3 = pWorkerR3; … … 2735 2630 2736 2631 PVIRTIONETVIRTQ pCtlVirtq = &pThis->aVirtqs[CTRLQIDX]; 2737 int rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, CTRLQIDX /* idxWorker */,2632 int rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, CTRLQIDX /* uIdxWorker */, 2738 2633 &pThis->aWorkers[CTRLWIDX], &pThisCC->aWorkers[CTRLWIDX], pCtlVirtq); 2739 2634 AssertRCReturn(rc, rc); … … 2741 2636 pCtlVirtq->fHasWorker = true; 2742 2637 2743 uint16_t idxWorker = CTRLWIDX + 1;2744 for (uint16_t uVirtqPair = 0; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++, idxWorker++)2638 uint16_t uIdxWorker = CTRLWIDX + 1; 2639 for (uint16_t uVirtqPair = pThis->cInitializedVirtqPairs; uVirtqPair < pThis->cVirtqPairs; uVirtqPair++, uIdxWorker++) 2745 2640 { 2746 2641 PVIRTIONETVIRTQ pTxVirtq = &pThis->aVirtqs[TXQIDX(uVirtqPair)]; 2747 2642 PVIRTIONETVIRTQ pRxVirtq = &pThis->aVirtqs[RXQIDX(uVirtqPair)]; 2748 2643 2749 rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, idxWorker, &pThis->aWorkers[idxWorker],2750 &pThisCC->aWorkers[ idxWorker], pTxVirtq);2644 rc = virtioNetR3CreateOneWorkerThread(pDevIns, pThis, uIdxWorker, &pThis->aWorkers[uIdxWorker], 2645 &pThisCC->aWorkers[uIdxWorker], pTxVirtq); 2751 2646 AssertRCReturn(rc, rc); 2752 2647 … … 2754 2649 pRxVirtq->fHasWorker = false; 2755 2650 } 2651 2652 if (pThis->cVirtqPairs > pThis->cInitializedVirtqPairs) 2653 pThis->cInitializedVirtqPairs = pThis->cVirtqPairs; 2654 2756 2655 pThis->cWorkers = pThis->cVirtqPairs + 1 /* One control virtq */; 2757 2656 return rc; … … 2775 2674 /** @todo Race w/guest enabling/disabling guest notifications cyclically. 2776 2675 See BugRef #8651, Comment #82 */ 2777 virtioCoreVirtqEnableNotify(&pThis->Virtio, pVirtq->idx, true /* fEnable */); 2778 2779 while (pThread->enmState == PDMTHREADSTATE_RUNNING) 2780 { 2781 if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pVirtq->idx)) 2676 virtioCoreVirtqEnableNotify(&pThis->Virtio, pVirtq->uIdx, true /* fEnable */); 2677 2678 while ( pThread->enmState != PDMTHREADSTATE_TERMINATING 2679 && pThread->enmState != PDMTHREADSTATE_TERMINATED) 2680 { 2681 if (IS_VIRTQ_EMPTY(pDevIns, &pThis->Virtio, pVirtq->uIdx)) 2782 2682 { 2783 2683 /* Atomic interlocks avoid missing alarm while going to sleep & notifier waking the awoken */ … … 2802 2702 /* Dispatch to the handler for the queue this worker is set up to drive */ 2803 2703 2804 if (!pThisCC->fQuiescing) 2805 { 2806 if (pVirtq->fCtlVirtq) 2704 if (pVirtq->fCtlVirtq) 2705 { 2706 Log10Func(("%s %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName)); 2707 PVIRTQBUF pVirtqBuf = NULL; 2708 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pVirtq->uIdx, &pVirtqBuf, true); 2709 if (rc == VERR_NOT_AVAILABLE) 2807 2710 { 2808 Log10Func(("%s %s worker woken. Fetching desc chain\n", pThis->szInst, pVirtq->szName)); 2809 PVIRTQBUF pVirtqBuf = NULL; 2810 int rc = virtioCoreR3VirtqAvailBufGet(pDevIns, &pThis->Virtio, pVirtq->idx, &pVirtqBuf, true); 2811 if (rc == VERR_NOT_AVAILABLE) 2812 { 2813 Log10Func(("%s %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName)); 2814 continue; 2815 } 2816 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pVirtqBuf); 2817 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 2711 Log10Func(("%s %s worker woken. Nothing found in queue/n", pThis->szInst, pVirtq->szName)); 2712 continue; 2818 2713 } 2819 else /* Must be Tx queue */ 2820 { 2821 Log10Func(("%s %s worker woken. Virtq has data to transmit\n", pThis->szInst, pVirtq->szName)); 2822 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */); 2823 } 2824 2825 /* Rx queues aren't handled by our worker threads. Instead, the PDM network 2826 * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, 2827 * which waits until notified directly by virtioNetVirtqNotified() 2828 * that guest IN buffers have been added to receive virt queue. 2829 */ 2830 } 2714 virtioNetR3Ctrl(pDevIns, pThis, pThisCC, pVirtqBuf); 2715 virtioCoreR3VirtqBufRelease(&pThis->Virtio, pVirtqBuf); 2716 } 2717 else /* Must be Tx queue */ 2718 { 2719 Log10Func(("%s %s worker woken. Virtq has data to transmit\n", pThis->szInst, pVirtq->szName)); 2720 virtioNetR3TransmitPendingPackets(pDevIns, pThis, pThisCC, pVirtq, false /* fOnWorkerThread */); 2721 } 2722 2723 /* Rx queues aren't handled by our worker threads. Instead, the PDM network 2724 * leaf driver invokes PDMINETWORKDOWN.pfnWaitReceiveAvail() callback, 2725 * which waits until woken by virtioNetVirtqNotified() 2726 * indicating that guest IN buffers have been added to Rx virt queue. 2727 */ 2831 2728 } 2832 2729 Log10(("%s %s worker thread exiting\n", pThis->szInst, pVirtq->szName)); … … 2859 2756 2860 2757 pThis->fResetting = false; 2861 pThisCC->fQuiescing = false;2862 2758 2863 2759 for (unsigned uVirtqNbr = 0; uVirtqNbr < pThis->cVirtVirtqs; uVirtqNbr++) 2864 2760 { 2865 2761 PVIRTIONETVIRTQ pVirtq = &pThis->aVirtqs[uVirtqNbr]; 2866 pVirtq-> idx = uVirtqNbr;2867 (void) virtioCoreR3VirtqAttach(&pThis->Virtio, pVirtq-> idx, pVirtq->szName);2762 pVirtq->uIdx = uVirtqNbr; 2763 (void) virtioCoreR3VirtqAttach(&pThis->Virtio, pVirtq->uIdx, pVirtq->szName); 2868 2764 pVirtq->fAttachedToVirtioCore = true; 2869 if (IS_VIRTQ_EMPTY(pThisCC->pDevIns, &pThis->Virtio, pVirtq-> idx))2870 virtioCoreVirtqEnableNotify(&pThis->Virtio, pVirtq-> idx, true /* fEnable */);2765 if (IS_VIRTQ_EMPTY(pThisCC->pDevIns, &pThis->Virtio, pVirtq->uIdx)) 2766 virtioCoreVirtqEnableNotify(&pThis->Virtio, pVirtq->uIdx, true /* fEnable */); 2871 2767 } 2872 2768 } … … 2916 2812 AssertLogRelReturnVoid(iLUN == 0); 2917 2813 2918 ENTER_CRITICAL_SECTION;2919 2920 2814 RT_NOREF(pThis); 2921 2815 … … 2925 2819 pThisCC->pDrvBase = NULL; 2926 2820 pThisCC->pDrv = NULL; 2927 2928 LEAVE_CRITICAL_SECTION;2929 2821 } 2930 2822 … … 2945 2837 AssertLogRelReturn(iLUN == 0, VERR_PDM_NO_SUCH_LUN); 2946 2838 2947 ENTER_CRITICAL_SECTION;2948 2949 2839 RT_NOREF(pThis); 2950 2840 … … 2960 2850 Log(("%s No attached driver!\n", pThis->szInst)); 2961 2851 2962 LEAVE_CRITICAL_SECTION;2963 2852 return rc; 2964 2853 } … … 3098 2987 # endif 3099 2988 3100 # if FEATURE_OFFERED(MQ) 3101 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_MAX_QPAIRS; 3102 # endif 2989 pThis->virtioNetConfig.uMaxVirtqPairs = VIRTIONET_CTRL_MQ_VQ_PAIRS_MAX; 3103 2990 3104 2991 pThisCC->Virtio.pfnVirtqNotified = virtioNetVirtqNotified; … … 3121 3008 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create event semaphore")); 3122 3009 3123 /* Initialize VirtIO core. (pfnStatusChanged callback when VirtIO and guestare ready) */3010 /* Initialize VirtIO core. (pfnStatusChanged callback when both host VirtIO core & guest driver are ready) */ 3124 3011 rc = virtioCoreR3Init(pDevIns, &pThis->Virtio, &pThisCC->Virtio, &VirtioPciParams, pThis->szInst, 3125 3012 VIRTIONET_HOST_FEATURES_OFFERED, … … 3132 3019 return PDMDEV_SET_ERROR(pDevIns, rc, N_("virtio-net: Required features not successfully negotiated.")); 3133 3020 3134 pThis->cVirtqPairs = (pThis->fNegotiatedFeatures & VIRTIONET_F_MQ) 3135 ? pThis->virtioNetConfig.uMaxVirtqPairs : 1; 3021 pThis->cVirtqPairs = 1; /* default, VirtIO 1.0, 5.1.6.5.5 */ 3136 3022 3137 3023 pThis->cVirtVirtqs += pThis->cVirtqPairs * 2 + 1; … … 3152 3038 rc = virtioNetR3CreateWorkerThreads(pDevIns, pThis, pThisCC); 3153 3039 if (RT_FAILURE(rc)) 3154 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to worker threads"));3040 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to create worker threads")); 3155 3041 3156 3042 /* … … 3265 3151 /* .pfnMemSetup = */ NULL, 3266 3152 /* .pfnPowerOn = */ NULL, 3267 /* .pfnReset = */ virtioNetR3Reset,3268 /* .pfnSuspend = */ virtioNet R3Suspend,3269 /* .pfnResume = */ virtioNetR3Resume,3153 /* .pfnReset = */ NULL, 3154 /* .pfnSuspend = */ virtioNetWakeupRxBufWaiter, 3155 /* .pfnResume = */ NULL, 3270 3156 /* .pfnAttach = */ virtioNetR3Attach, 3271 3157 /* .pfnDetach = */ virtioNetR3Detach, 3272 3158 /* .pfnQueryInterface = */ NULL, 3273 3159 /* .pfnInitComplete = */ NULL, 3274 /* .pfnPowerOff = */ virtioNet R3PowerOff,3160 /* .pfnPowerOff = */ virtioNetWakeupRxBufWaiter, 3275 3161 /* .pfnSoftReset = */ NULL, 3276 3162 /* .pfnReserved0 = */ NULL,
Note:
See TracChangeset
for help on using the changeset viewer.