VirtualBox

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

Last change on this file since 76681 was 76553, checked in by vboxsync, 6 years ago

scm --update-copyright-year

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