Changeset 81122 in vbox
- Timestamp:
- Oct 7, 2019 8:54:00 AM (5 years ago)
- Location:
- trunk/src/VBox/Devices
- Files:
-
- 4 edited
-
Storage/DevVirtioSCSI.cpp (modified) (13 diffs)
-
VirtIO/Virtio_1_0.cpp (modified) (16 diffs)
-
VirtIO/Virtio_1_0.h (modified) (3 diffs)
-
VirtIO/Virtio_1_0_impl.h (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp
r81021 r81122 27 27 #include <VBox/vmm/pdmstorageifs.h> 28 28 #include <VBox/vmm/pdmcritsect.h> 29 #include <VBox/msi.h> 29 30 #include <VBox/version.h> 30 31 #include <VBox/log.h> … … 79 80 * TEMPORARY NOTE: following parameter is set to 1 for early development. Will be increased later 80 81 */ 81 #define VIRTIOSCSI_REQ_QUEUE_CNT 2 /**< Number of req queues exposed by dev. */ 82 //#define VIRTIOSCSI_REQ_QUEUE_CNT 2 /**< Number of req queues exposed by dev. */ 83 //#define VIRTIOSCSI_QUEUE_CNT VIRTIOSCSI_REQ_QUEUE_CNT + 2 84 //#define VIRTIOSCSI_MAX_LUN 256 /* < VirtIO specification, section 5.6.4 */ 85 //#define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 1 /* < T.B.D. What is a good value for this? */ 86 //#define VIRTIOSCSI_MAX_SEG_COUNT 1024 /* < T.B.D. What is a good value for this? */ 87 //#define VIRTIOSCSI_MAX_SECTORS_HINT 0x10000 /* < VirtIO specification, section 5.6.4 */ 88 //#define VIRTIOSCSI_MAX_CHANNEL_HINT 0 /* < VirtIO specification, section 5.6.4 should be 0 */ 89 //#define VIRTIOSCSI_SAVED_STATE_MINOR_VERSION 0x01 /**< SSM version # */ 90 91 92 #define VIRTIOSCSI_REQ_QUEUE_CNT 1 /**< Number of req queues exposed by dev. */ 82 93 #define VIRTIOSCSI_QUEUE_CNT VIRTIOSCSI_REQ_QUEUE_CNT + 2 83 94 #define VIRTIOSCSI_MAX_LUN 256 /* < VirtIO specification, section 5.6.4 */ 84 #define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 1 /* < T.B.D. What is a good value for this? */85 #define VIRTIOSCSI_MAX_SEG_COUNT 1 024/* < T.B.D. What is a good value for this? */95 #define VIRTIOSCSI_MAX_COMMANDS_PER_LUN 128 /* < T.B.D. What is a good value for this? */ 96 #define VIRTIOSCSI_MAX_SEG_COUNT 126 /* < T.B.D. What is a good value for this? */ 86 97 #define VIRTIOSCSI_MAX_SECTORS_HINT 0x10000 /* < VirtIO specification, section 5.6.4 */ 87 98 #define VIRTIOSCSI_MAX_CHANNEL_HINT 0 /* < VirtIO specification, section 5.6.4 should be 0 */ 88 99 #define VIRTIOSCSI_SAVED_STATE_MINOR_VERSION 0x01 /**< SSM version # */ 100 89 101 90 102 #define PCI_DEVICE_ID_VIRTIOSCSI_HOST 0x1048 /**< Informs guest driver of type of VirtIO device */ … … 169 181 pMediaExTxDirEnumValue == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE 170 182 /** 171 * Following struct is the VirtIO SCSI Host Device device-specific configuration described in section 5.6.4 172 * of the VirtIO 1.0 spec. Layout maps an MMIO area shared VirtIO guest driver. The VBox VirtIO 173 * this virtual controller device implementation is a client of. Framework does a callback whenever 174 * guest driver accesses any part of field in this struct 183 * The following struct is the VirtIO SCSI Host Device device-specific configuration described 184 * in section 5.6.4 of the VirtIO 1.0 spec. The VBox VirtIO framework calls back to this driver 185 * to handle MMIO accesses to the device-specific configuration parameters whenever any bytes in the 186 * device-specific region areaccessed, since which the generic portion shouldn't know anything about 187 * the device-specific VirtIO cfg data. 175 188 */ 176 189 typedef struct virtio_scsi_config … … 187 200 uint32_t uMaxLun; /**< max_lun Hint to guest driver */ 188 201 } VIRTIOSCSI_CONFIG_T, PVIRTIOSCSI_CONFIG_T; 189 190 202 191 203 /** … … 479 491 R3PTRTYPE(PPDMILEDCONNECTORS) pLedsConnector; 480 492 481 /** Base address of the memory mapping. */482 RTGCPHYS GCPhysMMIOBase;483 484 493 /** IMediaExPort: Media ejection notification */ 485 494 R3PTRTYPE(PPDMIMEDIANOTIFY) pMediaNotify; … … 493 502 /** Mask of VirtIO Async Event types this device will deliver */ 494 503 uint32_t uAsyncEvtsEnabled; 495 496 /** The event semaphore the processing thread waits on. */497 498 504 499 505 /** Total number of requests active across all targets */ … … 1002 1008 || (VIRTIO_OUT_DIRECTION(pReq->enmTxDir) && cbXfer32 > pReq->cbDataOut)) 1003 1009 { 1004 /* TBD try to figure out optimal sense info to send back besides response of VIRTIOSCSI_S_OVERRUN */1005 1010 Log2Func((" * * * * Data overrun, returning sense\n")); 1006 1011 uint8_t abSense[] = { RT_BIT(7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED, … … 1038 1043 RTSgBufInit(&reqSegBuf, aReqSegs, cSegs); 1039 1044 1040 /*1041 * Fill in the request queue current descriptor chain's IN queue entry/entries1042 * (phys. memory) with the Req response data in virtual memory.1043 */1044 1045 size_t cbReqSgBuf = RTSgBufCalcTotalLength(&reqSegBuf); 1045 1046 AssertMsgReturn(cbReqSgBuf <= pReq->pDescChain->cbPhysDst, … … 1104 1105 * Handle submission errors 1105 1106 */ 1106 if ( pThis->fResetting)1107 if (RT_UNLIKELY(pThis->fResetting)) 1107 1108 { 1108 1109 Log2Func(("Aborting req submission because reset is in progress\n")); … … 1116 1117 } 1117 1118 else 1118 if ( uTarget >= pThis->cTargets || uScsiLun != 0)1119 if (RT_UNLIKELY(uTarget >= pThis->cTargets || uScsiLun != 0)) 1119 1120 { 1120 1121 Log2Func(("Error submitting request to bad target (%d) or bad LUN (%d)\n", uTarget, uScsiLun)); … … 1140 1141 respHdr.uStatus = SCSI_STATUS_CHECK_CONDITION; 1141 1142 respHdr.uResponse = VIRTIOSCSI_S_TARGET_FAILURE; 1143 respHdr.uResidual = cbDataIn + cbDataOut; 1144 virtioScsiReqErr(pThis, qIdx, pDescChain, &respHdr , abSense); 1145 return VINF_SUCCESS; 1146 } 1147 else 1148 if (RT_UNLIKELY(cbDataIn && cbDataOut && !pThis->fHasInOutBufs)) /* VirtIO 1.0, 5.6.6.1.1 */ 1149 { 1150 Log2Func(("Error submitting request, got datain & dataout bufs w/o INOUT feature negotated\n")); 1151 uint8_t abSense[] = { RT_BIT(7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED, 1152 0, SCSI_SENSE_ILLEGAL_REQUEST, 0, 0, 0, 0, 10, 0, 0, 0 }; 1153 struct REQ_RESP_HDR respHdr = { 0 }; 1154 respHdr.uSenseLen = sizeof(abSense); 1155 respHdr.uStatus = SCSI_STATUS_CHECK_CONDITION; 1156 respHdr.uResponse = VIRTIOSCSI_S_FAILURE; 1142 1157 respHdr.uResidual = cbDataIn + cbDataOut; 1143 1158 virtioScsiReqErr(pThis, qIdx, pDescChain, &respHdr , abSense); … … 1758 1773 1759 1774 /* Wake worker threads flagged to skip pulling queue entries during quiesce 1760 * to ensure they re-check their queues. Active request queues may already1761 * be awake due to new reqs coming in.1775 * to ensure they re-check their queues. Active request queues may already 1776 * be awake due to new reqs coming in. 1762 1777 */ 1763 1778 for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++) … … 2386 2401 /* .cbInstanceRC = */ 0, 2387 2402 /* .cMaxPciDevices = */ 1, 2388 /* .cMaxMsixVectors = */ 0,2403 /* .cMaxMsixVectors = */ VBOX_MSIX_MAX_ENTRIES, 2389 2404 /* .pszDescription = */ "Virtio Host SCSI.\n", 2390 2405 #if defined(IN_RING3) -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp
r81031 r81122 366 366 367 367 AssertMsgReturnVoid(DRIVER_OK(pVirtio), ("Guest driver not in ready state.\n")); 368 369 if (pVirtio->uMsixConfig == VIRTIO_MSI_NO_VECTOR) 370 { 371 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 372 { 373 if (pVirtq->fEventThresholdReached) 374 { 375 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce); 376 pVirtq->fEventThresholdReached = false; 377 return; 378 } 379 Log6Func(("...skipping interrupt: VIRTIO_F_EVENT_IDX set but threshold not reached\n")); 380 } 381 else 382 { 383 /** If guest driver hasn't suppressed interrupts, interrupt */ 384 if (fForce || !(virtioReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 385 { 386 virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, fForce); 387 return; 388 } 389 Log6Func(("...skipping interrupt. Guest flagged VIRTQ_AVAIL_F_NO_INTERRUPT for queue\n")); 390 } 391 } 392 else 393 { 394 /* TBD, do MSI notification if criteria met */ 368 if (pVirtio->uDriverFeatures & VIRTIO_F_EVENT_IDX) 369 { 370 if (pVirtq->fEventThresholdReached) 371 { 372 virtioKick(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uQueueMsixVector[qIdx], fForce); 373 pVirtq->fEventThresholdReached = false; 374 return; 375 } 376 Log6Func(("...skipping interrupt: VIRTIO_F_EVENT_IDX set but threshold not reached\n")); 377 } 378 else 379 { 380 /** If guest driver hasn't suppressed interrupts, interrupt */ 381 if (fForce || !(virtioReadUsedFlags(pVirtio, qIdx) & VIRTQ_AVAIL_F_NO_INTERRUPT)) 382 { 383 virtioKick(pVirtio, VIRTIO_ISR_VIRTQ_INTERRUPT, pVirtio->uQueueMsixVector[qIdx], fForce); 384 return; 385 } 386 Log6Func(("...skipping interrupt. Guest flagged VIRTQ_AVAIL_F_NO_INTERRUPT for queue\n")); 395 387 } 396 388 } … … 425 417 } 426 418 427 /** 428 * Raise interrupt. 419 420 /** 421 * Raise interrupt or MSI-X 429 422 * 430 423 * @param pVirtio The device state structure. 431 424 * @param uCause Interrupt cause bit mask to set in PCI ISR port. 432 */ 433 static int virtioRaiseInterrupt(PVIRTIOSTATE pVirtio, uint8_t uCause, bool fForce) 425 * @param uVec MSI-X vector, if enabled 426 * @param uForce True of out-of-band 427 */ 428 static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uMsixVector, bool fForce) 434 429 { 435 430 … … 443 438 Log6Func(("reason: device config change\n")); 444 439 445 pVirtio->uISR |= uCause; 446 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 1); 440 if (!pVirtio->fMsiSupport) 441 { 442 pVirtio->uISR |= uCause; 443 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, PDM_IRQ_LEVEL_HIGH); 444 } 445 else if (uMsixVector != VIRTIO_MSI_NO_VECTOR) 446 { 447 Log6Func(("MSI-X enabled, calling PDMDevHlpPCISetIrq with vector: 0x%x\n", uMsixVector)); 448 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), uMsixVector, 1); 449 } 447 450 return VINF_SUCCESS; 448 451 } … … 455 458 static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio) 456 459 { 457 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0);460 PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, PDM_IRQ_LEVEL_LOW); 458 461 } 459 462 … … 466 469 pVirtio->uQueueSize[qIdx] = VIRTQ_MAX_SIZE; 467 470 pVirtio->uQueueNotifyOff[qIdx] = qIdx; 468 } 469 471 472 pVirtio->uQueueMsixVector[qIdx] = qIdx + 2; 473 if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */ 474 pVirtio->uQueueMsixVector[qIdx] = VIRTIO_MSI_NO_VECTOR; 475 } 470 476 471 477 static void virtioResetDevice(PVIRTIOSTATE pVirtio) … … 478 484 pVirtio->uISR = 0; 479 485 480 #ifndef MSIX_SUPPORT 481 /** This is required by VirtIO 1.0 specification, section 4.1.5.1.2 */ 482 pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR; 483 for (int i = 0; i < VIRTQ_MAX_CNT; i++) 484 pVirtio->uQueueMsixVector[i] = VIRTIO_MSI_NO_VECTOR; 485 #endif 486 487 if (!pVirtio->fMsiSupport) /* VirtIO 1.0, 4.1.4.3 and 4.1.5.1.2 */ 488 pVirtio->uMsixConfig = VIRTIO_MSI_NO_VECTOR; 486 489 487 490 pVirtio->uNumQueues = VIRTQ_MAX_CNT; … … 523 526 { 524 527 pVirtio->fGenUpdatePending = true; 525 virtio RaiseInterrupt(pVirtio, VIRTIO_ISR_DEVICE_CONFIG, false /* fForce */);528 virtioKick(pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */); 526 529 } 527 530 } … … 529 532 /** 530 533 * Invoked by this implementation when guest driver resets the device. 531 * The driver itself will not resetuntil the device has read the status change.534 * The driver itself will not until the device has read the status change. 532 535 */ 533 536 static void virtioGuestResetted(PVIRTIOSTATE pVirtio) … … 1015 1018 VIRTIOHANDLE *phVirtio, 1016 1019 PVIRTIOPCIPARAMS pPciParams, 1017 const char *pcszInstance,1020 const char *pcszInstance, 1018 1021 uint64_t uDevSpecificFeatures, 1019 1022 PFNVIRTIODEVCAPREAD devCapReadCallback, … … 1028 1031 void *pDevSpecificCfg) 1029 1032 { 1033 1034 extern PDMDEVREG g_DeviceVirtioSCSI; 1035 1030 1036 PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAllocZ(sizeof(VIRTIOSTATE)); 1031 1037 if (!pVirtio) … … 1034 1040 return VERR_NO_MEMORY; 1035 1041 } 1042 1043 #ifdef VBOX_WITH_MSI_DEVICES 1044 pVirtio->fMsiSupport = true; 1045 #endif 1036 1046 1037 1047 pVirtio->pClientContext = pClientContext; … … 1109 1119 1110 1120 /* Construct & map PCI vendor-specific capabilities for virtio host negotiation with guest driver */ 1111 1112 #if 0 && defined(VBOX_WITH_MSI_DEVICES) /* T.B.D. */1113 uint8_t fMsiSupport = true;1114 #else1115 uint8_t fMsiSupport = false;1116 #endif1117 1121 1118 1122 /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T) … … 1184 1188 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR; 1185 1189 pCfg->uCapLen = sizeof(VIRTIO_PCI_CFG_CAP_T); 1186 pCfg->uCapNext = ( fMsiSupport || pVirtio->pDevSpecificCfg) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;1190 pCfg->uCapNext = (pVirtio->fMsiSupport || pVirtio->pDevSpecificCfg) ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1187 1191 pCfg->uBar = 0; 1188 1192 pCfg->uOffset = 0; … … 1199 1203 pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR; 1200 1204 pCfg->uCapLen = sizeof(VIRTIO_PCI_CAP_T); 1201 pCfg->uCapNext = fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0;1205 pCfg->uCapNext = pVirtio->fMsiSupport ? CFGADDR2IDX(pCfg) + pCfg->uCapLen : 0; 1202 1206 pCfg->uBar = VIRTIO_REGION_PCI_CAP; 1203 1207 pCfg->uOffset = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength; … … 1208 1212 } 1209 1213 1210 /* Set offset to first capability and enable PCI dev capabilities */ 1211 PDMPciDevSetCapabilityList(pPciDev, 0x40); 1212 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); 1213 1214 if (fMsiSupport) 1214 if (pVirtio->fMsiSupport) 1215 1215 { 1216 1216 PDMMSIREG aMsiReg; … … 1218 1218 aMsiReg.iMsixCapOffset = pCfg->uCapNext; 1219 1219 aMsiReg.iMsixNextOffset = 0; 1220 aMsiReg.iMsixBar = 0;1221 aMsiReg.cMsixVectors = 1;1220 aMsiReg.iMsixBar = VIRTIO_REGION_MSIX_CAP; 1221 aMsiReg.cMsixVectors = g_DeviceVirtioSCSI.cMaxMsixVectors; 1222 1222 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &aMsiReg); /* see MsixR3init() */ 1223 if (RT_FAILURE (rc)) 1224 /* The following is moot, we need to flag no MSI-X support */ 1225 PDMPciDevSetCapabilityList(pPciDev, 0x40); 1226 } 1223 if (RT_FAILURE(rc)) 1224 { 1225 /* See PDMDevHlp.cpp:pdmR3DevHlp_PCIRegisterMsi */ 1226 Log(("Failed to configure MSI-X (%Rrc). Reverting to INTx\n")); 1227 pVirtio->fMsiSupport = false; 1228 } 1229 else 1230 Log(("Using MSI-X for guest driver notification\n")); 1231 } 1232 else 1233 Log(("MSI-X not available for VBox, using INTx notification\n")); 1234 1235 1236 /* Set offset to first capability and enable PCI dev capabilities */ 1237 PDMPciDevSetCapabilityList(pPciDev, 0x40); 1238 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); 1227 1239 1228 1240 /* Linux drivers/virtio/virtio_pci_modern.c tries to map at least a page for the -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0.h
r80931 r81122 39 39 #define VIRTIO_NOTIFY_OFFSET_MULTIPLIER 2 /**< VirtIO Notify Cap. MMIO config param */ 40 40 #define VIRTIO_REGION_PCI_CAP 2 /**< BAR for VirtIO Cap. MMIO (impl specific) */ 41 #define VIRTIO_REGION_MSIX_CAP 0 /**< Bar for MSI-X handling */ 41 42 42 43 #define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \ … … 163 164 /** 164 165 * Allocate client context for client to work with VirtIO-provided with queue 165 * As a side effect creates a buffer vector a client can get a pointer to166 * with a call to virtioQueueDescChain()167 166 * 168 167 * @param hVirtio - Handle to VirtIO framework … … 211 210 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments 212 211 * and a pointer to the descriptor chain context originally derived from the pulled 213 * queue entry, and this function will putwrite the virtual memory s/g buffer into the212 * queue entry, and this function will write the virtual memory s/g buffer into the 214 213 * guest's physical memory free the descriptor chain. The caller handles the freeing 215 214 * (as needed) of the virtual memory buffer. -
trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h
r81031 r81122 189 189 uint8_t uPciCfgDataOff; 190 190 uint8_t uISR; /**< Interrupt Status Register. */ 191 uint8_t fMsiSupport; 191 192 192 193 } VIRTIOSTATE, *PVIRTIOSTATE; … … 520 521 static void virtioResetQueue (PVIRTIOSTATE pVirtio, uint16_t qIdx); 521 522 static void virtioNotifyGuestDriver (PVIRTIOSTATE pVirtio, uint16_t qIdx, bool fForce); 522 static int virtioRaiseInterrupt (PVIRTIOSTATE pVirtio, uint8_t uCause, bool fForce); 523 static void virtioLowerInterrupt (PVIRTIOSTATE pVirtio); 523 static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uVec, bool fForce); 524 524 static void virtioQueueNotified (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx); 525 525 static void virtioGuestResetted (PVIRTIOSTATE pVirtio);
Note:
See TracChangeset
for help on using the changeset viewer.

