VirtualBox

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

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

VMM,Devices: Some PDM device model refactoring. bugref:9218

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.2 KB
Line 
1/* $Id: DevPciMerge1.cpp.h 80531 2019-09-01 23:03:34Z 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 * @param pfnConfigRead The default config read method.
63 * @param pfnConfigWrite The default config read method.
64 *
65 * @remarks Caller enters the PDM critical section.
66 */
67static int pciR3MergedRegisterDeviceOnBus(PPDMDEVINS pDevIns, PDEVPCIBUS pBus, PPDMPCIDEV pPciDev, uint32_t fFlags,
68 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName,
69 PFNPCICONFIGREAD pfnConfigRead, PFNPCICONFIGWRITE pfnConfigWrite)
70{
71 /*
72 * Validate input.
73 */
74 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
75 AssertPtrReturn(pPciDev, VERR_INVALID_POINTER);
76 AssertReturn(!(fFlags & ~PDMPCIDEVREG_F_VALID_MASK), VERR_INVALID_FLAGS);
77 AssertReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES || uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
78 AssertReturn(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS || uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, VERR_INVALID_PARAMETER);
79
80 /*
81 * Assign device & function numbers.
82 */
83
84 /* Work the optional assignment flag. */
85 if (fFlags & PDMPCIDEVREG_F_NOT_MANDATORY_NO)
86 {
87 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES && uPciFunNo < VBOX_PCI_MAX_FUNCTIONS,
88 ("PDMPCIDEVREG_F_NOT_MANDATORY_NO not implemented for #Dev=%#x / #Fun=%#x\n", uPciDevNo, uPciFunNo),
89 VERR_NOT_IMPLEMENTED);
90 if (pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)])
91 {
92 uPciDevNo = PDMPCIDEVREG_DEV_NO_FIRST_UNUSED;
93 uPciFunNo = PDMPCIDEVREG_FUN_NO_FIRST_UNUSED;
94 }
95 }
96
97 if (uPciDevNo == PDMPCIDEVREG_DEV_NO_FIRST_UNUSED)
98 {
99 /* Just find the next unused device number and we're good. */
100 uPciDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
101 AssertLogRelMsgReturn(uPciDevNo < VBOX_PCI_MAX_DEVICES, ("Couldn't find a free spot!\n"), VERR_PDM_TOO_PCI_MANY_DEVICES);
102 if (uPciFunNo == PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
103 uPciFunNo = 0;
104 }
105 else
106 {
107 /*
108 * Direct assignment of device number can be more complicated.
109 */
110 PPDMPCIDEV pClash;
111 if (uPciFunNo != PDMPCIDEVREG_FUN_NO_FIRST_UNUSED)
112 {
113 /* In the case of a specified function, we only relocate an existing
114 device if it belongs to a different device instance. Reasoning is
115 that the device should figure out it's own function assignments.
116 Note! We could make this more flexible by relocating functions assigned
117 via PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, but it can wait till it's needed. */
118 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
119 if (!pClash)
120 { /* likely */ }
121 else if (pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3)
122 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (same pDevIns)!\n",
123 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
124 VERR_PDM_TOO_PCI_MANY_DEVICES);
125 else if (!pClash->Int.s.fReassignableDevNo)
126 AssertLogRelMsgFailedReturn(("PCI Configuration conflict at %u.%u: %s vs %s (different pDevIns)!\n",
127 uPciDevNo, uPciFunNo, pClash->pszNameR3, pszName),
128 VERR_PDM_TOO_PCI_MANY_DEVICES);
129 }
130 else
131 {
132 /* First unused function slot. Again, we only relocate the whole
133 thing if all the device instance differs, because we otherwise
134 reason that a device should manage its own functions correctly. */
135 unsigned cSameDevInses = 0;
136 for (uPciFunNo = 0, pClash = NULL; uPciFunNo < VBOX_PCI_MAX_FUNCTIONS; uPciFunNo++)
137 {
138 pClash = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)];
139 if (!pClash)
140 break;
141 cSameDevInses += pClash->Int.s.pDevInsR3 == pPciDev->Int.s.pDevInsR3;
142 }
143 if (!pClash)
144 Assert(uPciFunNo < VBOX_PCI_MAX_FUNCTIONS);
145 else
146 AssertLogRelMsgReturn(cSameDevInses == 0,
147 ("PCI Configuration conflict at %u.* appending %s (%u of %u pDevIns matches)!\n",
148 uPciDevNo, pszName, cSameDevInses, VBOX_PCI_MAX_FUNCTIONS),
149 VERR_PDM_TOO_PCI_MANY_DEVICES);
150 }
151 if (pClash)
152 {
153 /*
154 * Try relocate the existing device.
155 */
156 /* Check that all functions can be moved. */
157 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
158 {
159 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
160 AssertLogRelMsgReturn(!pMovePciDev || pMovePciDev->Int.s.fReassignableDevNo,
161 ("PCI Configuration conflict at %u.%u: %s vs %s\n",
162 uPciDevNo, uMoveFun, pMovePciDev->pszNameR3, pszName),
163 VERR_PDM_TOO_PCI_MANY_DEVICES);
164 }
165
166 /* Find a free device number to move it to. */
167 uint8_t uMoveToDevNo = pciR3MergedFindUnusedDeviceNo(pBus);
168 Assert(uMoveToDevNo != uPciFunNo);
169 AssertLogRelMsgReturn(uMoveToDevNo < VBOX_PCI_MAX_DEVICES,
170 ("No space to relocate device at %u so '%s' can be placed there instead!\n", uPciFunNo, pszName),
171 VERR_PDM_TOO_PCI_MANY_DEVICES);
172
173 /* Execute the move. */
174 for (uint8_t uMoveFun = 0; uMoveFun < VBOX_PCI_MAX_FUNCTIONS; uMoveFun++)
175 {
176 PPDMPCIDEV pMovePciDev = pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)];
177 if (pMovePciDev)
178 {
179 Log(("PCI: Relocating '%s' from %u.%u to %u.%u.\n", pMovePciDev->pszNameR3, uPciDevNo, uMoveFun, uMoveToDevNo, uMoveFun));
180 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uMoveFun)] = NULL;
181 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun)] = pMovePciDev;
182 pMovePciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uMoveToDevNo, uMoveFun);
183 }
184 }
185 }
186 }
187
188 /*
189 * Now, initialize the rest of the PCI device structure.
190 */
191 Assert(!pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)]);
192 pBus->apDevices[VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo)] = pPciDev;
193
194 pPciDev->uDevFn = VBOX_PCI_DEVFN_MAKE(uPciDevNo, uPciFunNo);
195 pPciDev->Int.s.pBusR3 = pBus;
196 Assert(pBus == PDMINS_2_DATA(pDevIns, PDEVPCIBUS));
197 pPciDev->Int.s.pBusR0 = PDMINS_2_DATA_R0PTR(pDevIns);
198 pPciDev->Int.s.pBusRC = PDMINS_2_DATA_RCPTR(pDevIns);
199 pPciDev->Int.s.pfnConfigRead = pfnConfigRead;
200 pPciDev->Int.s.pfnConfigWrite = pfnConfigWrite;
201
202 /* Remember and mark bridges. */
203 if (fFlags & PDMPCIDEVREG_F_PCI_BRIDGE)
204 {
205 AssertLogRelMsgReturn(pBus->cBridges < RT_ELEMENTS(pBus->apDevices),
206 ("Number of bridges exceeds the number of possible devices on the bus\n"),
207 VERR_INTERNAL_ERROR_3);
208 pBus->papBridgesR3[pBus->cBridges++] = pPciDev;
209 pciDevSetPci2PciBridge(pPciDev);
210 }
211
212 Log(("PCI: Registered device %d function %d (%#x) '%s'.\n",
213 uPciDevNo, uPciFunNo, UINT32_C(0x80000000) | (pPciDev->uDevFn << 8), pszName));
214
215 return VINF_SUCCESS;
216}
217
218
219/**
220 * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
221 */
222static DECLCALLBACK(int) pciR3MergedRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
223 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
224{
225 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
226 AssertCompileMemberOffset(DEVPCIROOT, PciBus, 0);
227 return pciR3MergedRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName,
228 devpciR3CommonDefaultConfigRead, devpciR3CommonDefaultConfigWrite);
229}
230
231
232/**
233 * @interface_method_impl{PDMPCIBUSREG,pfnRegisterR3}
234 */
235static DECLCALLBACK(int) pcibridgeR3MergedRegisterDevice(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags,
236 uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)
237{
238 PDEVPCIBUS pBus = PDMINS_2_DATA(pDevIns, PDEVPCIBUS);
239 return pciR3MergedRegisterDeviceOnBus(pDevIns, pBus, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName,
240 devpciR3CommonDefaultConfigRead, devpciR3CommonDefaultConfigWrite);
241}
242
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