VirtualBox

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

Last change on this file since 77750 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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