int MsiInit(PPCIDEVICE pDev, PPDMMSIREG pMsiReg) { if (pMsiReg->cMsiVectors == 0) return VINF_SUCCESS; /* We cannot init MSI on raw devices yet. */ Assert(!pciDevIsPassthrough(pDev)); uint16_t cVectors = pMsiReg->cMsiVectors; uint8_t iCapOffset = pMsiReg->iMsiCapOffset; uint8_t iNextOffset = pMsiReg->iMsiNextOffset; bool f64bit = pMsiReg->fMsi64bit; uint16_t iFlags = 0; int iMmc; /* Compute multiple-message capable bitfield */ for (iMmc = 0; iMmc < 6; iMmc++) { if ((1 << iMmc) >= cVectors) break; } if ((cVectors > VBOX_MSI_MAX_ENTRIES) || (1 << iMmc) < cVectors) return VERR_TOO_MUCH_DATA; Assert(iCapOffset != 0 && iCapOffset < 0xff && iNextOffset < 0xff); /* We always support per-vector masking */ iFlags |= VBOX_PCI_MSI_FLAGS_MASKBIT | iMmc; if (f64bit) iFlags |= VBOX_PCI_MSI_FLAGS_64BIT; /* How many vectors we're capable of */ iFlags |= iMmc; pDev->Int.s.u8MsiCapOffset = iCapOffset; pDev->Int.s.u8MsiCapSize = f64bit ? VBOX_MSI_CAP_SIZE_64 : VBOX_MSI_CAP_SIZE_32; PCIDevSetByte(pDev, iCapOffset + 0, VBOX_PCI_CAP_ID_MSI); PCIDevSetByte(pDev, iCapOffset + 1, iNextOffset); /* next */ PCIDevSetWord(pDev, iCapOffset + VBOX_MSI_CAP_MESSAGE_CONTROL, iFlags); *msiGetMaskBits(pDev) = 0; *msiGetPendingBits(pDev) = 0; pciDevSetMsiCapable(pDev); return VINF_SUCCESS; }
int MsixInit(PCPDMPCIHLP pPciHlp, PPCIDEVICE pDev, PPDMMSIREG pMsiReg) { if (pMsiReg->cMsixVectors == 0) return VINF_SUCCESS; /* We cannot init MSI-X on raw devices yet. */ Assert(!pciDevIsPassthrough(pDev)); uint16_t cVectors = pMsiReg->cMsixVectors; uint8_t iCapOffset = pMsiReg->iMsixCapOffset; uint8_t iNextOffset = pMsiReg->iMsixNextOffset; uint8_t iBar = pMsiReg->iMsixBar; if (cVectors > VBOX_MSIX_MAX_ENTRIES) { AssertMsgFailed(("Too many MSI-X vectors: %d\n", cVectors)); return VERR_TOO_MUCH_DATA; } if (iBar > 5) { AssertMsgFailed(("Using wrong BAR for MSI-X: %d\n", iBar)); return VERR_INVALID_PARAMETER; } Assert(iCapOffset != 0 && iCapOffset < 0xff && iNextOffset < 0xff); int rc = VINF_SUCCESS; /* If device is passthrough, BAR is registered using common mechanism. */ if (!pciDevIsPassthrough(pDev)) { rc = PDMDevHlpPCIIORegionRegister (pDev->pDevIns, iBar, 0x1000, PCI_ADDRESS_SPACE_MEM, msixMap); if (RT_FAILURE (rc)) return rc; } pDev->Int.s.u8MsixCapOffset = iCapOffset; pDev->Int.s.u8MsixCapSize = VBOX_MSIX_CAP_SIZE; PVM pVM = PDMDevHlpGetVM(pDev->pDevIns); pDev->Int.s.pMsixPageR3 = NULL; rc = MMHyperAlloc(pVM, 0x1000, 1, MM_TAG_PDM_DEVICE_USER, (void **)&pDev->Int.s.pMsixPageR3); if (RT_FAILURE(rc) || (pDev->Int.s.pMsixPageR3 == NULL)) return VERR_NO_VM_MEMORY; RT_BZERO(pDev->Int.s.pMsixPageR3, 0x1000); pDev->Int.s.pMsixPageR0 = MMHyperR3ToR0(pVM, pDev->Int.s.pMsixPageR3); pDev->Int.s.pMsixPageRC = MMHyperR3ToRC(pVM, pDev->Int.s.pMsixPageR3); /* R3 PCI helper */ pDev->Int.s.pPciBusPtrR3 = pPciHlp; PCIDevSetByte(pDev, iCapOffset + 0, VBOX_PCI_CAP_ID_MSIX); PCIDevSetByte(pDev, iCapOffset + 1, iNextOffset); /* next */ PCIDevSetWord(pDev, iCapOffset + VBOX_MSIX_CAP_MESSAGE_CONTROL, cVectors - 1); uint32_t offTable = 0, offPBA = 0x800; PCIDevSetDWord(pDev, iCapOffset + VBOX_MSIX_TABLE_BIROFFSET, offTable | iBar); PCIDevSetDWord(pDev, iCapOffset + VBOX_MSIX_PBA_BIROFFSET, offPBA | iBar); pciDevSetMsixCapable(pDev); return VINF_SUCCESS; }