VirtualBox

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

Last change on this file since 93492 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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