VirtualBox

source: vbox/trunk/src/VBox/Devices/Bus/DevPciMerge1.cpp.h@ 80943

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

Devices/PCI: Device model refactoring, part I. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.8 KB
Line 
1/* $Id: DevPciMerge1.cpp.h 80943 2019-09-23 09:36:14Z vboxsync $ */
2/** @file
3 * DevPci - Early attempt at common code for DevPci and DevPciIch9.
4 *
5 * @note Don't add more, add code to DevPciIch9.cpp instead.
6 * @note We'll keep this file like this for a little while longer
7 * because of 5.1.
8 */
9
10/*
11 * Copyright (C) 2004-2019 Oracle Corporation
12 *
13 * This file is part of VirtualBox Open Source Edition (OSE), as
14 * available from http://www.virtualbox.org. This file is free software;
15 * you can redistribute it and/or modify it under the terms of the GNU
16 * General Public License (GPL) as published by the Free Software
17 * Foundation, in version 2 as it comes in the "COPYING" file of the
18 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
19 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
20 */
21
22
23/**
24 * Search for a completely unused device entry (all 8 functions are unused).
25 *
26 * @returns VBox status code.
27 * @param pBus The bus to register with.
28 * @remarks Caller enters the PDM critical section.
29 */
30static uint8_t pciR3MergedFindUnusedDeviceNo(PDEVPCIBUS pBus)
31{
32 for (uint8_t uPciDevNo = pBus->iDevSearch >> VBOX_PCI_DEVFN_DEV_SHIFT; uPciDevNo < VBOX_PCI_MAX_DEVICES; uPciDevNo++)
33 if ( !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 0)]
34 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 1)]
35 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 2)]
36 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 3)]
37 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 4)]
38 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 5)]
39 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 6)]
40 && !pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, 7)])
41 return uPciDevNo;
42 return UINT8_MAX;
43}
44
45
46
47/**
48 * Registers the device with the specified PCI bus.
49 *
50 * This is shared between the pci bus and pci bridge code.
51 *
52 * @returns VBox status code.
53 * @param pDevIns The PCI bus device instance.
54 * @param pBus The bus to register with.
55 * @param pPciDev The PCI device structure.
56 * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ.
57 * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific
58 * device number (0-31).
59 * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific
60 * function number (0-7).
61 * @param pszName Device name (static but not unique).
62 *
63 * @remarks Caller enters the PDM critical section.
64 */
65static int pciR3MergedRegisterDeviceOnBus(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags,
66 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
67{
68 /*
69 * Validate input.
70 */
71 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
72 AssertPtrReturn(pPciDev, VERR_INVALID_POINTER);
73 AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS);
74 AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
75 AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
76
77 /*
78 * Assign device & function numbers.
79 */
80
81 /* Work the optional assignment flag. */
82 if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO)
83 {
84 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS,
85 ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo),
86 VERR_NOT_IMPLEMENTED);
87 if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)])
88 {
89 uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
90 uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED;
91 }
92 }
93
94 if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED)
95 {
96 /* Just find the next unused device number and we're good. */
97 uPciDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
98 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES);
99 if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
100 uPciFunNo = 0;
101 }
102 else
103 {
104 /*
105 * Direct assignment of device number can be more complicated.
106 */
107 PPDMPCIDEV pClash;
108 if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
109 {
110 /* In the case of a specified function, we only relocate an existing
111 device if it belongs to a different device instance. Reasoning is
112 that the device should figure out it's own function assignments.
113 Note! We could make this more flexible by relocating functions assigned
114 via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */
115 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
116 if (!pClash)
117 { /* likely */ }
118 else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3)
119 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n",
120 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
121 VERR_PDM_TOO_PCI_MANY_DEVICES);
122 else if (!pClash->Int.s.fReassignableDevNo)
123 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n",
124 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
125 VERR_PDM_TOO_PCI_MANY_DEVICES);
126 }
127 else
128 {
129 /* First unused function slot. Again, we only relocate the whole
130 thing if all the device instance differs, because we otherwise
131 reason that a device should manage its own functions correctly. */
132 unsigned cSameDevInses = 0;
133 for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++)
134 {
135 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
136 if (!pClash)
137 break;
138 cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3;
139 }
140 if (!pClash)
141 Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS);
142 else
143 AssertLogRelMsgReturn(cSameDevInses == 0,
144 ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n",
145 uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS),
146 VERR_PDM_TOO_PCI_MANY_DEVICES);
147 }
148 if (pClash)
149 {
150 /*
151 * Try relocate the existing device.
152 */
153 /* Check that all functions can be moved. */
154 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
155 {
156 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
157 AssertLogRelMsgReturn(!pMovePciDev || pMovePciDev->Int.s.fReassignableDevNo,
158 ("PCI Configuration conflict at %u.%u: %s vs %s\n",
159 uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName),
160 VERR_PDM_TOO_PCI_MANY_DEVICES);
161 }
162
163 /* Find a free device number to move it to. */
164 uint8_t uMoveToDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
165 Assert(uMoveToDevNo != uPciFunNo);
166 AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES,
167 ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName),
168 VERR_PDM_TOO_PCI_MANY_DEVICES);
169
170 /* Execute the move. */
171 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
172 {
173 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
174 if (pMovePciDev)
175 {
176 Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun));
177 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL;
178 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev;
179 pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun);
180 }
181 }
182 }
183 }
184
185 /*
186 * Now, initialize the rest of the PCI device structure.
187 */
188 Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]);
189 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev;
190
191 pPciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo);
192 pPciDev->Int.s.pBusR3 = pBus;
193 Assert(pBus == PDMINS_2_DATA(pDevIns, PDEVPCIBUS));
194 pPciDev->Int.s.pBusR0 = PDMINS_2_DATA_R0PTR(pDevIns);
195 pPciDev->Int.s.pBusRC = PDMINS_2_DATA_RCPTR(pDevIns);
196 pPciDev->Int.s.pfnConfigRead = NULL;
197 pPciDev->Int.s.pfnConfigWrite = NULL;
198
199 /* Remember and mark bridges. */
200 if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE)
201 {
202 AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices),
203 ("Number of bridges exceeds the number of possible devices on the bus\n"),
204 VERR_INTERNAL_ERROR_3);
205 pBus->papBridgesR3[pBus->cBridges++] = pPciDev;
206 pciDevSetPci2PciBridge(pPciDev);
207 }
208
209 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
210 uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName));
211
212 return VINF_SUCCESS;
213}
214
215
216/**
217 * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
218 */
219static DECLCALLBACK(int) pciR3MergedRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
220 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
221{
222 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
223 AssertCompileMemberOffset(DEVPCIROOT, PciBus, 0);
224 return pciR3MergedRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
225}
226
227
228/**
229 * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
230 */
231static DECLCALLBACK(int) pcibridgeR3MergedRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
232 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
233{
234 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
235 return pciR3MergedRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName);
236}
237
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