/** @interface_method_impl{PDMDEVREG,pfnConstruct} */ static DECLCALLBACK(int) ox958R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) { RT_NOREF(iInstance); PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958); bool fRCEnabled = true; bool fR0Enabled = true; bool fMsiXSupported = false; int rc; PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); /* * Validate and read configuration. */ if (!CFGMR3AreValuesValid(pCfg, "RCEnabled\0" "R0Enabled\0" "MsiXSupported\0" "UartCount\0")) return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES, N_("OXPCIe958 configuration error: Unknown option specified")); rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: Failed to read \"RCEnabled\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"R0Enabled\" as boolean")); rc = CFGMR3QueryBoolDef(pCfg, "MsiXSupported", &fMsiXSupported, true); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"MsiXSupported\" as boolean")); rc = CFGMR3QueryU32Def(pCfg, "UartCount", &pThis->cUarts, OX958_UARTS_MAX); if (RT_FAILURE(rc)) return PDMDEV_SET_ERROR(pDevIns, rc, N_("OXPCIe958 configuration error: failed to read \"UartCount\" as unsigned 32bit integer")); if (!pThis->cUarts || pThis->cUarts > OX958_UARTS_MAX) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("OXPCIe958 configuration error: \"UartCount\" has invalid value %u (must be in range [1 .. %u]"), pThis->cUarts, OX958_UARTS_MAX); /* * Init instance data. */ pThis->fR0Enabled = fR0Enabled; pThis->fRCEnabled = fRCEnabled; pThis->pDevInsR3 = pDevIns; pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns); pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns); /* Fill PCI config space. */ PDMPciDevSetVendorId (&pThis->PciDev, OX958_PCI_VENDOR_ID); PDMPciDevSetDeviceId (&pThis->PciDev, OX958_PCI_DEVICE_ID); PDMPciDevSetCommand (&pThis->PciDev, 0x0000); #ifdef VBOX_WITH_MSI_DEVICES PDMPciDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST); PDMPciDevSetCapabilityList (&pThis->PciDev, OX958_PCI_MSI_CAP_OFS); #else PDMPciDevSetCapabilityList (&pThis->PciDev, 0x70); #endif PDMPciDevSetRevisionId (&pThis->PciDev, 0x00); PDMPciDevSetClassBase (&pThis->PciDev, 0x07); /* Communication controller. */ PDMPciDevSetClassSub (&pThis->PciDev, 0x00); /* Serial controller. */ PDMPciDevSetClassProg (&pThis->PciDev, 0x02); /* 16550. */ PDMPciDevSetRevisionId (&pThis->PciDev, 0x00); PDMPciDevSetSubSystemVendorId(&pThis->PciDev, OX958_PCI_VENDOR_ID); PDMPciDevSetSubSystemId (&pThis->PciDev, OX958_PCI_DEVICE_ID); PDMPciDevSetInterruptLine (&pThis->PciDev, 0x00); PDMPciDevSetInterruptPin (&pThis->PciDev, 0x01); /** @todo More Capabilities. */ rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns)); if (RT_FAILURE(rc)) return rc; /* * Register PCI device and I/O region. */ rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev); if (RT_FAILURE(rc)) return rc; #ifdef VBOX_WITH_MSI_DEVICES PDMMSIREG MsiReg; RT_ZERO(MsiReg); MsiReg.cMsiVectors = 1; MsiReg.iMsiCapOffset = OX958_PCI_MSI_CAP_OFS; MsiReg.iMsiNextOffset = OX958_PCI_MSIX_CAP_OFS; MsiReg.fMsi64bit = true; if (fMsiXSupported) { MsiReg.cMsixVectors = VBOX_MSIX_MAX_ENTRIES; MsiReg.iMsixCapOffset = OX958_PCI_MSIX_CAP_OFS; MsiReg.iMsixNextOffset = 0x00; MsiReg.iMsixBar = OX958_PCI_MSIX_BAR; } rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); if (RT_FAILURE(rc)) { PCIDevSetCapabilityList(&pThis->PciDev, 0x0); /* That's OK, we can work without MSI */ } #endif rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, _16K, PCI_ADDRESS_SPACE_MEM, ox958R3Map); if (RT_FAILURE(rc)) return rc; PVM pVM = PDMDevHlpGetVM(pDevIns); RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR; RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR; if ( fRCEnabled && VM_IS_RAW_MODE_ENABLED(pVM)) { rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->szRCMod, "ox958IrqReq", &pfnSerialIrqReqRC); if (RT_FAILURE(rc)) return rc; } if (fR0Enabled) { rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->szR0Mod, "ox958IrqReq", &pfnSerialIrqReqR0); if (RT_FAILURE(rc)) return rc; } for (uint32_t i = 0; i < pThis->cUarts; i++) { POX958UART pUart = &pThis->aUarts[i]; rc = uartR3Init(&pUart->UartCore, pDevIns, UARTTYPE_16550A, i, 0, ox958IrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC); if (RT_FAILURE(rc)) return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, N_("OXPCIe958 configuration error: failed to initialize UART %u"), i); } ox958R3Reset(pDevIns); 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; }