VirtualBox

source: vbox/trunk/src/VBox/Devices/Serial/DevOxPcie958.cpp@ 80957

Last change on this file since 80957 was 80704, checked in by vboxsync, 5 years ago

PDM,Devices: Changed PDM_DEVREG_FLAGS_MSI_X into a registration field giving the max MSI-X vector count config for the device (typically VBOX_MSIX_MAX_ENTRIES). bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.9 KB
Line 
1/* $Id: DevOxPcie958.cpp 80704 2019-09-10 15:19:39Z vboxsync $ */
2/** @file
3 * DevOxPcie958 - Oxford Semiconductor OXPCIe958 PCI Express bridge to octal serial port emulation
4 */
5
6/*
7 * Copyright (C) 2018-2019 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/** @page pg_dev_oxpcie958 OXPCIe958 - Oxford Semiconductor OXPCIe958 PCI Express bridge to octal serial port emulation.
19 * @todo Write something
20 */
21
22
23/*********************************************************************************************************************************
24* Header Files *
25*********************************************************************************************************************************/
26#define LOG_GROUP LOG_GROUP_DEV_SERIAL
27#include <VBox/pci.h>
28#include <VBox/msi.h>
29#include <VBox/vmm/pdm.h>
30#include <VBox/vmm/pdmpci.h>
31#include <VBox/err.h>
32#include <VBox/log.h>
33#include <iprt/assert.h>
34#include <iprt/list.h>
35#include <iprt/asm.h>
36
37#include "VBoxDD.h"
38#include "UartCore.h"
39
40
41/** @name PCI device related constants.
42 * @} */
43/** The PCI device ID. */
44#define OX958_PCI_DEVICE_ID 0xc308
45/** The PCI vendor ID. */
46#define OX958_PCI_VENDOR_ID 0x1415
47/** Where the MSI capability starts. */
48#define OX958_PCI_MSI_CAP_OFS 0x80
49/** Where the MSI-X capability starts. */
50#define OX958_PCI_MSIX_CAP_OFS (OX958_PCI_MSI_CAP_OFS + VBOX_MSI_CAP_SIZE_64)
51/** The BAR for the MSI-X related functionality. */
52#define OX958_PCI_MSIX_BAR 1
53/** @} */
54
55/** Maximum number of UARTs supported by the device. */
56#define OX958_UARTS_MAX 16
57
58/** Offset op the class code and revision ID register. */
59#define OX958_REG_CC_REV_ID 0x00
60/** Offset fof the UART count register. */
61#define OX958_REG_UART_CNT 0x04
62/** Offset of the global UART IRQ status register. */
63#define OX958_REG_UART_IRQ_STS 0x08
64/** Offset of the global UART IRQ enable register. */
65#define OX958_REG_UART_IRQ_ENABLE 0x0c
66/** Offset of the global UART IRQ disable register. */
67#define OX958_REG_UART_IRQ_DISABLE 0x10
68/** Offset of the global UART wake IRQ enable register. */
69#define OX958_REG_UART_WAKE_IRQ_ENABLE 0x14
70/** Offset of the global UART wake IRQ disable register. */
71#define OX958_REG_UART_WAKE_IRQ_DISABLE 0x18
72/** Offset of the region in MMIO space where the UARTs actually start. */
73#define OX958_REG_UART_REGION_OFFSET 0x1000
74/** Register region size for each UART. */
75#define OX958_REG_UART_REGION_SIZE 0x200
76/** Offset where the DMA channels registers start for each UART. */
77#define OX958_REG_UART_DMA_REGION_OFFSET 0x100
78
79
80/**
81 * OXPCIe958 UART core.
82 */
83typedef struct OX958UART
84{
85 /** The UART core. */
86 UARTCORE UartCore;
87 /** DMA address configured. */
88 RTGCPHYS GCPhysDmaAddr;
89 /** The DMA transfer length configured. */
90 uint32_t cbDmaXfer;
91 /** The DMA status registers. */
92 uint32_t u32RegDmaSts;
93} OX958UART;
94/** Pointer to a OXPCIe958 UART core. */
95typedef OX958UART *POX958UART;
96
97
98/**
99 * OXPCIe958 device instance data.
100 */
101typedef struct DEVOX958
102{
103 /** The corresponding PCI device. */
104 PDMPCIDEV PciDev;
105
106 /** Pointer to the device instance - R3 ptr. */
107 PPDMDEVINSR3 pDevInsR3;
108 /** Pointer to the device instance - R0 ptr */
109 PPDMDEVINSR0 pDevInsR0;
110 /** Pointer to the device instance - RC ptr. */
111 PPDMDEVINSRC pDevInsRC;
112 /** Flag whether R0 is enabled. */
113 bool fR0Enabled;
114 /** Flag whether RC is enabled. */
115 bool fRCEnabled;
116 /** Alignment. */
117 bool afAlignment[2];
118 /** UART global IRQ status. */
119 volatile uint32_t u32RegIrqStsGlob;
120 /** UART global IRQ enable mask. */
121 volatile uint32_t u32RegIrqEnGlob;
122 /** UART wake IRQ enable mask. */
123 volatile uint32_t u32RegIrqEnWake;
124 /** Number of UARTs configured. */
125 uint32_t cUarts;
126 /** MMIO Base address. */
127 RTGCPHYS GCPhysMMIO;
128 /** The UARTs. */
129 OX958UART aUarts[OX958_UARTS_MAX];
130
131} DEVOX958;
132/** Pointer to an OXPCIe958 device instance. */
133typedef DEVOX958 *PDEVOX958;
134
135#ifndef VBOX_DEVICE_STRUCT_TESTCASE
136
137
138
139/**
140 * Update IRQ status of the device.
141 *
142 * @returns nothing.
143 * @param pThis The OXPCIe958 device instance.
144 */
145static void ox958IrqUpdate(PDEVOX958 pThis)
146{
147 uint32_t u32IrqSts = ASMAtomicReadU32(&pThis->u32RegIrqStsGlob);
148 uint32_t u32IrqEn = ASMAtomicReadU32(&pThis->u32RegIrqEnGlob);
149
150 if (u32IrqSts & u32IrqEn)
151 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, PDM_IRQ_LEVEL_HIGH);
152 else
153 PDMDevHlpPCISetIrq(pThis->CTX_SUFF(pDevIns), 0, PDM_IRQ_LEVEL_LOW);
154}
155
156
157/**
158 * Performs a register read from the given UART.
159 *
160 * @returns nothing.
161 * @param pThis The OXPCIe958 device instance.
162 * @param pUart The UART accessed.
163 * @param offUartReg Offset of the register being read.
164 * @param pv Where to store the read data.
165 * @param cb Number of bytes to read.
166 */
167static int ox958UartRegRead(PDEVOX958 pThis, POX958UART pUart, uint32_t offUartReg, void *pv, unsigned cb)
168{
169 int rc = VINF_SUCCESS;
170 RT_NOREF(pThis);
171
172 if (offUartReg >= OX958_REG_UART_DMA_REGION_OFFSET)
173 {
174 /* Access to the DMA registers. */
175 }
176 else /* Access UART registers. */
177 rc = uartRegRead(&pUart->UartCore, offUartReg, (uint32_t *)pv, cb);
178
179 return rc;
180}
181
182
183/**
184 * Performs a register write to the given UART.
185 *
186 * @returns nothing.
187 * @param pThis The OXPCIe958 device instance.
188 * @param pUart The UART accessed.
189 * @param offUartReg Offset of the register being written.
190 * @param pv The data to write.
191 * @param cb Number of bytes to write.
192 */
193static int ox958UartRegWrite(PDEVOX958 pThis, POX958UART pUart, uint32_t offUartReg, const void *pv, unsigned cb)
194{
195 int rc = VINF_SUCCESS;
196 RT_NOREF(pThis);
197
198 if (offUartReg >= OX958_REG_UART_DMA_REGION_OFFSET)
199 {
200 /* Access to the DMA registers. */
201 }
202 else /* Access UART registers. */
203 rc = uartRegWrite(&pUart->UartCore, offUartReg, *(const uint32_t *)pv, cb);
204
205 return rc;
206}
207
208
209/**
210 * UART core IRQ request callback.
211 *
212 * @returns nothing.
213 * @param pDevIns The device instance.
214 * @param pUart The UART requesting an IRQ update.
215 * @param iLUN The UART index.
216 * @param iLvl IRQ level requested.
217 */
218PDMBOTHCBDECL(void) ox958IrqReq(PPDMDEVINS pDevIns, PUARTCORE pUart, unsigned iLUN, int iLvl)
219{
220 RT_NOREF(pUart);
221 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
222
223 if (iLvl)
224 ASMAtomicOrU32(&pThis->u32RegIrqStsGlob, RT_BIT_32(iLUN));
225 else
226 ASMAtomicAndU32(&pThis->u32RegIrqStsGlob, ~RT_BIT_32(iLUN));
227 ox958IrqUpdate(pThis);
228}
229
230
231/**
232 * Read a MMIO register.
233 *
234 * @returns VBox status code suitable for scheduling.
235 * @param pDevIns The device instance.
236 * @param pvUser A user argument (ignored).
237 * @param GCPhysAddr The physical address being written to. (This is within our MMIO memory range.)
238 * @param pv Where to put the data we read.
239 * @param cb The size of the read.
240 */
241PDMBOTHCBDECL(int) ox958MmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)
242{
243 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
244 uint32_t offReg = (GCPhysAddr - pThis->GCPhysMMIO);
245 int rc = VINF_SUCCESS;
246 RT_NOREF(pThis, pvUser);
247
248 if (offReg < OX958_REG_UART_REGION_OFFSET)
249 {
250 uint32_t *pu32 = (uint32_t *)pv;
251 Assert(cb == 4);
252
253 switch (offReg)
254 {
255 case OX958_REG_CC_REV_ID:
256 *pu32 = 0x00070002;
257 break;
258 case OX958_REG_UART_CNT:
259 *pu32 = pThis->cUarts;
260 break;
261 case OX958_REG_UART_IRQ_STS:
262 *pu32 = ASMAtomicReadU32(&pThis->u32RegIrqStsGlob);
263 break;
264 case OX958_REG_UART_IRQ_ENABLE:
265 *pu32 = ASMAtomicReadU32(&pThis->u32RegIrqEnGlob);
266 break;
267 case OX958_REG_UART_IRQ_DISABLE:
268 *pu32 = ~ASMAtomicReadU32(&pThis->u32RegIrqEnGlob);
269 break;
270 case OX958_REG_UART_WAKE_IRQ_ENABLE:
271 *pu32 = ASMAtomicReadU32(&pThis->u32RegIrqEnWake);
272 break;
273 case OX958_REG_UART_WAKE_IRQ_DISABLE:
274 *pu32 = ~ASMAtomicReadU32(&pThis->u32RegIrqEnWake);
275 break;
276 default:
277 rc = VINF_IOM_MMIO_UNUSED_00;
278 }
279 }
280 else
281 {
282 /* Figure out the UART accessed from the offset. */
283 offReg -= OX958_REG_UART_REGION_OFFSET;
284 uint32_t iUart = offReg / OX958_REG_UART_REGION_SIZE;
285 uint32_t offUartReg = offReg % OX958_REG_UART_REGION_SIZE;
286 if (iUart < pThis->cUarts)
287 {
288 POX958UART pUart = &pThis->aUarts[iUart];
289 rc = ox958UartRegRead(pThis, pUart, offUartReg, pv, cb);
290 if (rc == VINF_IOM_R3_IOPORT_READ)
291 rc = VINF_IOM_R3_MMIO_READ;
292 }
293 else
294 rc = VINF_IOM_MMIO_UNUSED_00;
295 }
296
297 return rc;
298}
299
300
301/**
302 * Write to a MMIO register.
303 *
304 * @returns VBox status code suitable for scheduling.
305 * @param pDevIns The device instance.
306 * @param pvUser A user argument (ignored).
307 * @param GCPhysAddr The physical address being written to. (This is within our MMIO memory range.)
308 * @param pv Pointer to the data being written.
309 * @param cb The size of the data being written.
310 */
311PDMBOTHCBDECL(int) ox958MmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)
312{
313 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
314 uint32_t offReg = (GCPhysAddr - pThis->GCPhysMMIO);
315 int rc = VINF_SUCCESS;
316 RT_NOREF1(pvUser);
317
318 if (offReg < OX958_REG_UART_REGION_OFFSET)
319 {
320 const uint32_t u32 = *(const uint32_t *)pv;
321 Assert(cb == 4);
322
323 switch (offReg)
324 {
325 case OX958_REG_UART_IRQ_ENABLE:
326 ASMAtomicOrU32(&pThis->u32RegIrqEnGlob, u32);
327 ox958IrqUpdate(pThis);
328 break;
329 case OX958_REG_UART_IRQ_DISABLE:
330 ASMAtomicAndU32(&pThis->u32RegIrqEnGlob, ~u32);
331 ox958IrqUpdate(pThis);
332 break;
333 case OX958_REG_UART_WAKE_IRQ_ENABLE:
334 ASMAtomicOrU32(&pThis->u32RegIrqEnWake, u32);
335 break;
336 case OX958_REG_UART_WAKE_IRQ_DISABLE:
337 ASMAtomicAndU32(&pThis->u32RegIrqEnWake, ~u32);
338 break;
339 case OX958_REG_UART_IRQ_STS: /* Readonly */
340 case OX958_REG_CC_REV_ID: /* Readonly */
341 case OX958_REG_UART_CNT: /* Readonly */
342 default:
343 rc = VINF_SUCCESS;
344 }
345 }
346 else
347 {
348 /* Figure out the UART accessed from the offset. */
349 offReg -= OX958_REG_UART_REGION_OFFSET;
350 uint32_t iUart = offReg / OX958_REG_UART_REGION_SIZE;
351 uint32_t offUartReg = offReg % OX958_REG_UART_REGION_SIZE;
352 if (iUart < pThis->cUarts)
353 {
354 POX958UART pUart = &pThis->aUarts[iUart];
355 rc = ox958UartRegWrite(pThis, pUart, offUartReg, pv, cb);
356 if (rc == VINF_IOM_R3_IOPORT_WRITE)
357 rc = VINF_IOM_R3_MMIO_WRITE;
358 }
359 }
360
361 return rc;
362}
363
364
365#ifdef IN_RING3
366/**
367 * @callback_method_impl{FNPCIIOREGIONMAP}
368 */
369static DECLCALLBACK(int) ox958R3Map(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion,
370 RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)
371{
372 RT_NOREF(enmType);
373 PDEVOX958 pThis = (PDEVOX958)pPciDev;
374 int rc = VINF_SUCCESS;
375
376 if (iRegion == 0)
377 {
378 Assert(enmType == PCI_ADDRESS_SPACE_MEM);
379
380 rc = PDMDevHlpMMIORegister(pDevIns, GCPhysAddress, cb, NULL /*pvUser*/,
381 IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
382 ox958MmioWrite, ox958MmioRead, "OxPCIe958");
383 if (RT_FAILURE(rc))
384 return rc;
385
386 /* Enable (or not) RC/R0 support. */
387 if (pThis->fRCEnabled)
388 {
389 rc = PDMDevHlpMMIORegisterRC(pDevIns, GCPhysAddress, cb, NIL_RTRCPTR /*pvUser*/,
390 "ox958MmioWrite", "ox958MmioRead");
391 if (RT_FAILURE(rc))
392 return rc;
393 }
394
395 if (pThis->fR0Enabled)
396 {
397 rc = PDMDevHlpMMIORegisterR0(pDevIns, GCPhysAddress, cb, NIL_RTR0PTR /*pvUser*/,
398 "ox958MmioWrite", "ox958MmioRead");
399 if (RT_FAILURE(rc))
400 return rc;
401 }
402
403 pThis->GCPhysMMIO = GCPhysAddress;
404 }
405
406 return VINF_SUCCESS;
407}
408
409
410/** @interface_method_impl{PDMDEVREG,pfnDetach} */
411static DECLCALLBACK(void) ox958R3Detach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
412{
413 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
414 AssertReturnVoid(iLUN >= pThis->cUarts);
415
416 RT_NOREF(fFlags);
417
418 return uartR3Detach(&pThis->aUarts[iLUN].UartCore);
419}
420
421
422/** @interface_method_impl{PDMDEVREG,pfnAttach} */
423static DECLCALLBACK(int) ox958R3Attach(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)
424{
425 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
426
427 RT_NOREF(fFlags);
428
429 if (iLUN >= pThis->cUarts)
430 return VERR_PDM_LUN_NOT_FOUND;
431
432 return uartR3Attach(&pThis->aUarts[iLUN].UartCore, iLUN);
433}
434
435
436/** @interface_method_impl{PDMDEVREG,pfnReset} */
437static DECLCALLBACK(void) ox958R3Reset(PPDMDEVINS pDevIns)
438{
439 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
440
441 pThis->u32RegIrqStsGlob = 0x00;
442 pThis->u32RegIrqEnGlob = 0x00;
443 pThis->u32RegIrqEnWake = 0x00;
444
445 for (uint32_t i = 0; i < pThis->cUarts; i++)
446 uartR3Reset(&pThis->aUarts[i].UartCore);
447}
448
449
450/** @interface_method_impl{PDMDEVREG,pfnRelocate} */
451static DECLCALLBACK(void) ox958R3Relocate(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)
452{
453 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
454 RT_NOREF(offDelta);
455
456 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
457 for (uint32_t i = 0; i < pThis->cUarts; i++)
458 uartR3Relocate(&pThis->aUarts[i].UartCore, offDelta);
459}
460
461
462/** @interface_method_impl{PDMDEVREG,pfnDestruct} */
463static DECLCALLBACK(int) ox958R3Destruct(PPDMDEVINS pDevIns)
464{
465 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
466 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns);
467
468 for (uint32_t i = 0; i < pThis->cUarts; i++)
469 uartR3Destruct(&pThis->aUarts[i].UartCore);
470
471 return VINF_SUCCESS;
472}
473
474
475/** @interface_method_impl{PDMDEVREG,pfnConstruct} */
476static DECLCALLBACK(int) ox958R3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)
477{
478 RT_NOREF(iInstance);
479 PDEVOX958 pThis = PDMINS_2_DATA(pDevIns, PDEVOX958);
480 bool fRCEnabled = true;
481 bool fR0Enabled = true;
482 bool fMsiXSupported = false;
483 int rc;
484
485 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
486
487 /*
488 * Validate and read configuration.
489 */
490 if (!CFGMR3AreValuesValid(pCfg, "RCEnabled\0"
491 "R0Enabled\0"
492 "MsiXSupported\0"
493 "UartCount\0"))
494 return PDMDEV_SET_ERROR(pDevIns, VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES,
495 N_("OXPCIe958 configuration error: Unknown option specified"));
496
497 rc = CFGMR3QueryBoolDef(pCfg, "RCEnabled", &fRCEnabled, true);
498 if (RT_FAILURE(rc))
499 return PDMDEV_SET_ERROR(pDevIns, rc,
500 N_("OXPCIe958 configuration error: Failed to read \"RCEnabled\" as boolean"));
501
502 rc = CFGMR3QueryBoolDef(pCfg, "R0Enabled", &fR0Enabled, true);
503 if (RT_FAILURE(rc))
504 return PDMDEV_SET_ERROR(pDevIns, rc,
505 N_("OXPCIe958 configuration error: failed to read \"R0Enabled\" as boolean"));
506
507 rc = CFGMR3QueryBoolDef(pCfg, "MsiXSupported", &fMsiXSupported, true);
508 if (RT_FAILURE(rc))
509 return PDMDEV_SET_ERROR(pDevIns, rc,
510 N_("OXPCIe958 configuration error: failed to read \"MsiXSupported\" as boolean"));
511
512 rc = CFGMR3QueryU32Def(pCfg, "UartCount", &pThis->cUarts, OX958_UARTS_MAX);
513 if (RT_FAILURE(rc))
514 return PDMDEV_SET_ERROR(pDevIns, rc,
515 N_("OXPCIe958 configuration error: failed to read \"UartCount\" as unsigned 32bit integer"));
516
517 if (!pThis->cUarts || pThis->cUarts > OX958_UARTS_MAX)
518 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
519 N_("OXPCIe958 configuration error: \"UartCount\" has invalid value %u (must be in range [1 .. %u]"),
520 pThis->cUarts, OX958_UARTS_MAX);
521
522 /*
523 * Init instance data.
524 */
525 pThis->fR0Enabled = fR0Enabled;
526 pThis->fRCEnabled = fRCEnabled;
527 pThis->pDevInsR3 = pDevIns;
528 pThis->pDevInsR0 = PDMDEVINS_2_R0PTR(pDevIns);
529 pThis->pDevInsRC = PDMDEVINS_2_RCPTR(pDevIns);
530
531 /* Fill PCI config space. */
532 PDMPciDevSetVendorId (&pThis->PciDev, OX958_PCI_VENDOR_ID);
533 PDMPciDevSetDeviceId (&pThis->PciDev, OX958_PCI_DEVICE_ID);
534 PDMPciDevSetCommand (&pThis->PciDev, 0x0000);
535#ifdef VBOX_WITH_MSI_DEVICES
536 PDMPciDevSetStatus (&pThis->PciDev, VBOX_PCI_STATUS_CAP_LIST);
537 PDMPciDevSetCapabilityList (&pThis->PciDev, OX958_PCI_MSI_CAP_OFS);
538#else
539 PDMPciDevSetCapabilityList (&pThis->PciDev, 0x70);
540#endif
541 PDMPciDevSetRevisionId (&pThis->PciDev, 0x00);
542 PDMPciDevSetClassBase (&pThis->PciDev, 0x07); /* Communication controller. */
543 PDMPciDevSetClassSub (&pThis->PciDev, 0x00); /* Serial controller. */
544 PDMPciDevSetClassProg (&pThis->PciDev, 0x02); /* 16550. */
545
546 PDMPciDevSetRevisionId (&pThis->PciDev, 0x00);
547 PDMPciDevSetSubSystemVendorId(&pThis->PciDev, OX958_PCI_VENDOR_ID);
548 PDMPciDevSetSubSystemId (&pThis->PciDev, OX958_PCI_DEVICE_ID);
549
550 PDMPciDevSetInterruptLine (&pThis->PciDev, 0x00);
551 PDMPciDevSetInterruptPin (&pThis->PciDev, 0x01);
552 /** @todo More Capabilities. */
553
554 rc = PDMDevHlpSetDeviceCritSect(pDevIns, PDMDevHlpCritSectGetNop(pDevIns));
555 if (RT_FAILURE(rc))
556 return rc;
557
558 /*
559 * Register PCI device and I/O region.
560 */
561 rc = PDMDevHlpPCIRegister(pDevIns, &pThis->PciDev);
562 if (RT_FAILURE(rc))
563 return rc;
564
565#ifdef VBOX_WITH_MSI_DEVICES
566 PDMMSIREG MsiReg;
567 RT_ZERO(MsiReg);
568 MsiReg.cMsiVectors = 1;
569 MsiReg.iMsiCapOffset = OX958_PCI_MSI_CAP_OFS;
570 MsiReg.iMsiNextOffset = OX958_PCI_MSIX_CAP_OFS;
571 MsiReg.fMsi64bit = true;
572 if (fMsiXSupported)
573 {
574 MsiReg.cMsixVectors = VBOX_MSIX_MAX_ENTRIES;
575 MsiReg.iMsixCapOffset = OX958_PCI_MSIX_CAP_OFS;
576 MsiReg.iMsixNextOffset = 0x00;
577 MsiReg.iMsixBar = OX958_PCI_MSIX_BAR;
578 }
579 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg);
580 if (RT_FAILURE(rc))
581 {
582 PCIDevSetCapabilityList(&pThis->PciDev, 0x0);
583 /* That's OK, we can work without MSI */
584 }
585#endif
586
587 rc = PDMDevHlpPCIIORegionRegister(pDevIns, 0, _16K, PCI_ADDRESS_SPACE_MEM, ox958R3Map);
588 if (RT_FAILURE(rc))
589 return rc;
590
591 /** @todo This dynamic symbol resolving will be reworked later! */
592 PVM pVM = PDMDevHlpGetVM(pDevIns);
593 RTR0PTR pfnSerialIrqReqR0 = NIL_RTR0PTR;
594 RTRCPTR pfnSerialIrqReqRC = NIL_RTRCPTR;
595
596#ifdef VBOX_WITH_RAW_MODE_KEEP
597 if ( fRCEnabled
598 && VM_IS_RAW_MODE_ENABLED(pVM))
599 {
600 rc = PDMR3LdrGetSymbolRC(pVM, pDevIns->pReg->pszRCMod, "ox958IrqReq", &pfnSerialIrqReqRC);
601 if (RT_FAILURE(rc))
602 return rc;
603 }
604#endif
605
606 if (fR0Enabled)
607 {
608 rc = PDMR3LdrGetSymbolR0(pVM, pDevIns->pReg->pszR0Mod, "ox958IrqReq", &pfnSerialIrqReqR0);
609 if (RT_FAILURE(rc))
610 return rc;
611 }
612
613 for (uint32_t i = 0; i < pThis->cUarts; i++)
614 {
615 POX958UART pUart = &pThis->aUarts[i];
616 rc = uartR3Init(&pUart->UartCore, pDevIns, UARTTYPE_16550A, i, 0, ox958IrqReq, pfnSerialIrqReqR0, pfnSerialIrqReqRC);
617 if (RT_FAILURE(rc))
618 return PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS,
619 N_("OXPCIe958 configuration error: failed to initialize UART %u"), i);
620 }
621
622 ox958R3Reset(pDevIns);
623 return VINF_SUCCESS;
624}
625
626#endif /* IN_RING3 */
627
628
629const PDMDEVREG g_DeviceOxPcie958 =
630{
631 /* .u32version = */ PDM_DEVREG_VERSION,
632 /* .uReserved0 = */ 0,
633 /* .szName = */ "oxpcie958uart",
634 /* .fFlags = */ PDM_DEVREG_FLAGS_DEFAULT_BITS | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
635 /* .fClass = */ PDM_DEVREG_CLASS_SERIAL,
636 /* .cMaxInstances = */ ~0U,
637 /* .uSharedVersion = */ 42,
638 /* .cbInstanceShared = */ sizeof(DEVOX958),
639 /* .cbInstanceCC = */ 0,
640 /* .cbInstanceRC = */ 0,
641 /* .cMaxPciDevices = */ 1,
642 /* .cMaxMsixVectors = */ VBOX_MSIX_MAX_ENTRIES,
643 /* .pszDescription = */ "OXPCIe958 based UART controller.\n",
644#if defined(IN_RING3)
645 /* .pszRCMod = */ "VBoxDDRC.rc",
646 /* .pszR0Mod = */ "VBoxDDR0.r0",
647 /* .pfnConstruct = */ ox958R3Construct,
648 /* .pfnDestruct = */ ox958R3Destruct,
649 /* .pfnRelocate = */ ox958R3Relocate,
650 /* .pfnMemSetup = */ NULL,
651 /* .pfnPowerOn = */ NULL,
652 /* .pfnReset = */ ox958R3Reset,
653 /* .pfnSuspend = */ NULL,
654 /* .pfnResume = */ NULL,
655 /* .pfnAttach = */ ox958R3Attach,
656 /* .pfnDetach = */ ox958R3Detach,
657 /* .pfnQueryInterface = */ NULL,
658 /* .pfnInitComplete = */ NULL,
659 /* .pfnPowerOff = */ NULL,
660 /* .pfnSoftReset = */ NULL,
661 /* .pfnReserved0 = */ NULL,
662 /* .pfnReserved1 = */ NULL,
663 /* .pfnReserved2 = */ NULL,
664 /* .pfnReserved3 = */ NULL,
665 /* .pfnReserved4 = */ NULL,
666 /* .pfnReserved5 = */ NULL,
667 /* .pfnReserved6 = */ NULL,
668 /* .pfnReserved7 = */ NULL,
669#elif defined(IN_RING0)
670 /* .pfnEarlyConstruct = */ NULL,
671 /* .pfnConstruct = */ NULL,
672 /* .pfnDestruct = */ NULL,
673 /* .pfnFinalDestruct = */ NULL,
674 /* .pfnRequest = */ NULL,
675 /* .pfnReserved0 = */ NULL,
676 /* .pfnReserved1 = */ NULL,
677 /* .pfnReserved2 = */ NULL,
678 /* .pfnReserved3 = */ NULL,
679 /* .pfnReserved4 = */ NULL,
680 /* .pfnReserved5 = */ NULL,
681 /* .pfnReserved6 = */ NULL,
682 /* .pfnReserved7 = */ NULL,
683#elif defined(IN_RC)
684 /* .pfnConstruct = */ NULL,
685 /* .pfnReserved0 = */ NULL,
686 /* .pfnReserved1 = */ NULL,
687 /* .pfnReserved2 = */ NULL,
688 /* .pfnReserved3 = */ NULL,
689 /* .pfnReserved4 = */ NULL,
690 /* .pfnReserved5 = */ NULL,
691 /* .pfnReserved6 = */ NULL,
692 /* .pfnReserved7 = */ NULL,
693#else
694# error "Not in IN_RING3, IN_RING0 or IN_RC!"
695#endif
696 /* .u32VersionEnd = */ PDM_DEVREG_VERSION
697};
698
699#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */
700
Note: See TracBrowser for help on using the repository browser.

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