VirtualBox

Changeset 81122 in vbox


Ignore:
Timestamp:
Oct 7, 2019 8:54:00 AM (5 years ago)
Author:
vboxsync
Message:

Storage/DevVirtioSCSI.cpp: Got MSI-X support implemented and a few other small inconsequential tweaks

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Devices/Storage/DevVirtioSCSI.cpp

    r81021 r81122  
    2727#include <VBox/vmm/pdmstorageifs.h>
    2828#include <VBox/vmm/pdmcritsect.h>
     29#include <VBox/msi.h>
    2930#include <VBox/version.h>
    3031#include <VBox/log.h>
     
    7980 * TEMPORARY NOTE: following parameter is set to 1 for early development. Will be increased later
    8081 */
    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.            */
    8293#define VIRTIOSCSI_QUEUE_CNT                        VIRTIOSCSI_REQ_QUEUE_CNT + 2
    8394#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                    1024         /* < 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?           */
    8697#define VIRTIOSCSI_MAX_SECTORS_HINT                 0x10000      /* < VirtIO specification, section 5.6.4             */
    8798#define VIRTIOSCSI_MAX_CHANNEL_HINT                 0            /* < VirtIO specification, section 5.6.4 should be 0 */
    8899#define VIRTIOSCSI_SAVED_STATE_MINOR_VERSION        0x01         /**< SSM version #                                   */
     100
    89101
    90102#define PCI_DEVICE_ID_VIRTIOSCSI_HOST               0x1048       /**< Informs guest driver of type of VirtIO device   */
     
    169181            pMediaExTxDirEnumValue == PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE
    170182/**
    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.
    175188 */
    176189typedef struct virtio_scsi_config
     
    187200    uint32_t uMaxLun;                                            /**< max_lun          Hint to guest driver           */
    188201} VIRTIOSCSI_CONFIG_T, PVIRTIOSCSI_CONFIG_T;
    189 
    190202
    191203/**
     
    479491    R3PTRTYPE(PPDMILEDCONNECTORS)   pLedsConnector;
    480492
    481     /** Base address of the memory mapping. */
    482     RTGCPHYS                        GCPhysMMIOBase;
    483 
    484493    /** IMediaExPort: Media ejection notification */
    485494    R3PTRTYPE(PPDMIMEDIANOTIFY)     pMediaNotify;
     
    493502    /** Mask of VirtIO Async Event types this device will deliver */
    494503    uint32_t                        uAsyncEvtsEnabled;
    495 
    496     /** The event semaphore the processing thread waits on. */
    497 
    498504
    499505    /** Total number of requests active across all targets */
     
    10021008        || (VIRTIO_OUT_DIRECTION(pReq->enmTxDir) && cbXfer32 > pReq->cbDataOut))
    10031009    {
    1004         /* TBD try to figure out optimal sense info to send back besides response of VIRTIOSCSI_S_OVERRUN */
    10051010        Log2Func((" * * * * Data overrun, returning sense\n"));
    10061011        uint8_t abSense[] = { RT_BIT(7) | SCSI_SENSE_RESPONSE_CODE_CURR_FIXED,
     
    10381043        RTSgBufInit(&reqSegBuf, aReqSegs, cSegs);
    10391044
    1040         /*
    1041          * Fill in the request queue current descriptor chain's IN queue entry/entries
    1042          * (phys. memory) with the Req response data in virtual memory.
    1043          */
    10441045        size_t cbReqSgBuf = RTSgBufCalcTotalLength(&reqSegBuf);
    10451046        AssertMsgReturn(cbReqSgBuf <= pReq->pDescChain->cbPhysDst,
     
    11041105     * Handle submission errors
    11051106     */
    1106     if (pThis->fResetting)
     1107    if (RT_UNLIKELY(pThis->fResetting))
    11071108    {
    11081109        Log2Func(("Aborting req submission because reset is in progress\n"));
     
    11161117    }
    11171118    else
    1118     if (uTarget >= pThis->cTargets || uScsiLun != 0)
     1119    if (RT_UNLIKELY(uTarget >= pThis->cTargets || uScsiLun != 0))
    11191120    {
    11201121        Log2Func(("Error submitting request to bad target (%d) or bad LUN (%d)\n", uTarget, uScsiLun));
     
    11401141        respHdr.uStatus   = SCSI_STATUS_CHECK_CONDITION;
    11411142        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;
    11421157        respHdr.uResidual = cbDataIn + cbDataOut;
    11431158        virtioScsiReqErr(pThis, qIdx, pDescChain, &respHdr , abSense);
     
    17581773
    17591774    /* Wake worker threads flagged to skip pulling queue entries during quiesce
    1760      *  to ensure they re-check their queues. Active request queues may already
    1761      *  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.
    17621777     */
    17631778     for (uint16_t qIdx = 0; qIdx < VIRTIOSCSI_REQ_QUEUE_CNT; qIdx++)
     
    23862401    /* .cbInstanceRC = */           0,
    23872402    /* .cMaxPciDevices = */         1,
    2388     /* .cMaxMsixVectors = */        0,
     2403    /* .cMaxMsixVectors = */        VBOX_MSIX_MAX_ENTRIES,
    23892404    /* .pszDescription = */         "Virtio Host SCSI.\n",
    23902405#if defined(IN_RING3)
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0.cpp

    r81031 r81122  
    366366
    367367    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"));
    395387    }
    396388}
     
    425417}
    426418
    427 /**
    428  * Raise interrupt.
     419
     420/**
     421 * Raise interrupt or MSI-X
    429422 *
    430423 * @param   pVirtio         The device state structure.
    431424 * @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 */
     428static int virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uMsixVector, bool fForce)
    434429{
    435430
     
    443438       Log6Func(("reason: device config change\n"));
    444439
    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    }
    447450    return VINF_SUCCESS;
    448451}
     
    455458static void virtioLowerInterrupt(PVIRTIOSTATE pVirtio)
    456459{
    457     PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, 0);
     460    PDMDevHlpPCISetIrq(pVirtio->CTX_SUFF(pDevIns), 0, PDM_IRQ_LEVEL_LOW);
    458461}
    459462
     
    466469    pVirtio->uQueueSize[qIdx] = VIRTQ_MAX_SIZE;
    467470    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}
    470476
    471477static void virtioResetDevice(PVIRTIOSTATE pVirtio)
     
    478484    pVirtio->uISR                   = 0;
    479485
    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;
    486489
    487490    pVirtio->uNumQueues = VIRTQ_MAX_CNT;
     
    523526    {
    524527        pVirtio->fGenUpdatePending = true;
    525         virtioRaiseInterrupt(pVirtio, VIRTIO_ISR_DEVICE_CONFIG, false /* fForce */);
     528        virtioKick(pVirtio, VIRTIO_ISR_DEVICE_CONFIG, pVirtio->uMsixConfig, false /* fForce */);
    526529    }
    527530}
     
    529532/**
    530533 * Invoked by this implementation when guest driver resets the device.
    531  * The driver itself will not reset until the device has read the status change.
     534 * The driver itself will not until the device has read the status change.
    532535 */
    533536static void virtioGuestResetted(PVIRTIOSTATE pVirtio)
     
    10151018                      VIRTIOHANDLE          *phVirtio,
    10161019                      PVIRTIOPCIPARAMS       pPciParams,
    1017                       const char             *pcszInstance,
     1020                      const char            *pcszInstance,
    10181021                      uint64_t               uDevSpecificFeatures,
    10191022                      PFNVIRTIODEVCAPREAD    devCapReadCallback,
     
    10281031                      void                  *pDevSpecificCfg)
    10291032{
     1033
     1034    extern PDMDEVREG g_DeviceVirtioSCSI;
     1035
    10301036    PVIRTIOSTATE pVirtio = (PVIRTIOSTATE)RTMemAllocZ(sizeof(VIRTIOSTATE));
    10311037    if (!pVirtio)
     
    10341040        return VERR_NO_MEMORY;
    10351041    }
     1042
     1043#ifdef VBOX_WITH_MSI_DEVICES
     1044    pVirtio->fMsiSupport = true;
     1045#endif
    10361046
    10371047    pVirtio->pClientContext = pClientContext;
     
    11091119
    11101120    /* 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 #else
    1115     uint8_t fMsiSupport = false;
    1116 #endif
    11171121
    11181122    /* The following capability mapped via VirtIO 1.0: struct virtio_pci_cfg_cap (VIRTIO_PCI_CFG_CAP_T)
     
    11841188    pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
    11851189    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;
    11871191    pCfg->uBar     = 0;
    11881192    pCfg->uOffset  = 0;
     
    11991203        pCfg->uCapVndr = VIRTIO_PCI_CAP_ID_VENDOR;
    12001204        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;
    12021206        pCfg->uBar     = VIRTIO_REGION_PCI_CAP;
    12031207        pCfg->uOffset  = pVirtio->pIsrCap->uOffset + pVirtio->pIsrCap->uLength;
     
    12081212    }
    12091213
    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)
    12151215    {
    12161216        PDMMSIREG aMsiReg;
     
    12181218        aMsiReg.iMsixCapOffset  = pCfg->uCapNext;
    12191219        aMsiReg.iMsixNextOffset = 0;
    1220         aMsiReg.iMsixBar        = 0;
    1221         aMsiReg.cMsixVectors    = 1;
     1220        aMsiReg.iMsixBar        = VIRTIO_REGION_MSIX_CAP;
     1221        aMsiReg.cMsixVectors    = g_DeviceVirtioSCSI.cMaxMsixVectors;
    12221222        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);
    12271239
    12281240    /* 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  
    3939#define VIRTIO_NOTIFY_OFFSET_MULTIPLIER     2                    /**< VirtIO Notify Cap. MMIO config param     */
    4040#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                   */
    4142
    4243#define VIRTIO_HEX_DUMP(logLevel, pv, cb, base, title) \
     
    163164/**
    164165 * 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 to
    166  * with a call to virtioQueueDescChain()
    167166 *
    168167 * @param  hVirtio   - Handle to VirtIO framework
     
    211210 * The caller passes in a pointer to a scatter-gather buffer of virtual memory segments
    212211 * and a pointer to the descriptor chain context originally derived from the pulled
    213  * queue entry, and this function will put write the virtual memory s/g buffer into the
     212 * queue entry, and this function will write the virtual memory s/g buffer into the
    214213 * guest's physical memory free the descriptor chain. The caller handles the freeing
    215214 * (as needed) of the virtual memory buffer.
  • trunk/src/VBox/Devices/VirtIO/Virtio_1_0_impl.h

    r81031 r81122  
    189189    uint8_t                   uPciCfgDataOff;
    190190    uint8_t                   uISR;                              /**< Interrupt Status Register.                */
     191    uint8_t                   fMsiSupport;
    191192
    192193} VIRTIOSTATE, *PVIRTIOSTATE;
     
    520521static void virtioResetQueue        (PVIRTIOSTATE pVirtio, uint16_t qIdx);
    521522static 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);
     523static int  virtioKick(PVIRTIOSTATE pVirtio, uint8_t uCause, uint16_t uVec, bool fForce);
    524524static void virtioQueueNotified     (PVIRTIOSTATE pVirtio, uint16_t qidx, uint16_t uDescIdx);
    525525static void virtioGuestResetted     (PVIRTIOSTATE pVirtio);
Note: See TracChangeset for help on using the changeset viewer.

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