VirtualBox

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

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

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