VirtualBox

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

Last change on this file since 75265 was 73135, checked in by vboxsync, 6 years ago

Serial: Split out the generic UART functionality into a separate module so it can be reused.

Add a PCI Express 16 port UART controller emulation based on the Oxford Semiconductor OXPCIe958
PCI Express to octa UART controller (supports chaining two of those together in a single device
to get up to 16 UARTs). This somewhat revives the incomplete and never enabled PCI UART controller
in the old code. Linux detects the device and apparently configures all 16 UARTs but data transfers
were not tested and the code is pretty incomplete still.

  • 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 73135 2018-07-15 16:43:16Z vboxsync $ */
2/** @file
3 * DevOxPcie958 - Oxford Semiconductor OXPCIe958 PCI Express bridge to octal serial port emulation
4 */
5
6/*
7 * Copyright (C) 2018 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