26 |
26 |
#include "hw/pci/pci_bus.h"
|
27 |
27 |
#include "hw/pci/pcie_regs.h"
|
28 |
28 |
#include "qemu/range.h"
|
|
29 |
#include "qapi/qmp/qerror.h"
|
29 |
30 |
|
30 |
31 |
//#define DEBUG_PCIE
|
31 |
32 |
#ifdef DEBUG_PCIE
|
... | ... | |
216 |
217 |
hotplug_event_notify(dev);
|
217 |
218 |
}
|
218 |
219 |
|
219 |
|
static int pcie_cap_slot_hotplug(DeviceState *qdev,
|
220 |
|
PCIDevice *pci_dev, PCIHotplugState state)
|
|
220 |
static void pcie_cap_slot_hotplug_common(PCIDevice *hotplug_dev,
|
|
221 |
DeviceState *dev,
|
|
222 |
uint8_t **exp_cap, Error **errp)
|
221 |
223 |
{
|
222 |
|
PCIDevice *d = PCI_DEVICE(qdev);
|
223 |
|
uint8_t *exp_cap = d->config + d->exp.exp_cap;
|
224 |
|
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
|
225 |
|
|
226 |
|
/* Don't send event when device is enabled during qemu machine creation:
|
227 |
|
* it is present on boot, no hotplug event is necessary. We do send an
|
228 |
|
* event when the device is disabled later. */
|
229 |
|
if (state == PCI_COLDPLUG_ENABLED) {
|
230 |
|
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
231 |
|
PCI_EXP_SLTSTA_PDS);
|
232 |
|
return 0;
|
233 |
|
}
|
|
224 |
PCIDevice *pci_dev = PCI_DEVICE(dev);
|
|
225 |
*exp_cap = hotplug_dev->config + hotplug_dev->exp.exp_cap;
|
|
226 |
uint16_t sltsta = pci_get_word(*exp_cap + PCI_EXP_SLTSTA);
|
234 |
227 |
|
235 |
228 |
PCIE_DEV_PRINTF(pci_dev, "hotplug state: %d\n", state);
|
236 |
229 |
if (sltsta & PCI_EXP_SLTSTA_EIS) {
|
237 |
230 |
/* the slot is electromechanically locked.
|
238 |
231 |
* This error is propagated up to qdev and then to HMP/QMP.
|
239 |
232 |
*/
|
240 |
|
return -EBUSY;
|
|
233 |
error_setg_errno(errp, -EBUSY, "slot is electromechanically locked");
|
241 |
234 |
}
|
242 |
235 |
|
243 |
236 |
/* TODO: multifunction hot-plug.
|
... | ... | |
245 |
238 |
* hot plugged/unplugged.
|
246 |
239 |
*/
|
247 |
240 |
assert(PCI_FUNC(pci_dev->devfn) == 0);
|
|
241 |
}
|
248 |
242 |
|
249 |
|
if (state == PCI_HOTPLUG_ENABLED) {
|
|
243 |
void pcie_cap_slot_hotplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
244 |
Error **errp)
|
|
245 |
{
|
|
246 |
uint8_t *exp_cap;
|
|
247 |
|
|
248 |
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
|
249 |
|
|
250 |
/* Don't send event when device is enabled during qemu machine creation:
|
|
251 |
* it is present on boot, no hotplug event is necessary. We do send an
|
|
252 |
* event when the device is disabled later. */
|
|
253 |
if (!dev->hotplugged) {
|
250 |
254 |
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
251 |
255 |
PCI_EXP_SLTSTA_PDS);
|
252 |
|
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
|
253 |
|
} else {
|
254 |
|
object_unparent(OBJECT(pci_dev));
|
255 |
|
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
256 |
|
PCI_EXP_SLTSTA_PDS);
|
257 |
|
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
|
|
256 |
return;
|
258 |
257 |
}
|
259 |
|
return 0;
|
|
258 |
|
|
259 |
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
260 |
PCI_EXP_SLTSTA_PDS);
|
|
261 |
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
|
|
262 |
}
|
|
263 |
|
|
264 |
void pcie_cap_slot_hot_unplug_cb(HotplugHandler *hotplug_dev, DeviceState *dev,
|
|
265 |
Error **errp)
|
|
266 |
{
|
|
267 |
uint8_t *exp_cap;
|
|
268 |
|
|
269 |
pcie_cap_slot_hotplug_common(PCI_DEVICE(hotplug_dev), dev, &exp_cap, errp);
|
|
270 |
|
|
271 |
object_unparent(OBJECT(dev));
|
|
272 |
pci_word_test_and_clear_mask(exp_cap + PCI_EXP_SLTSTA,
|
|
273 |
PCI_EXP_SLTSTA_PDS);
|
|
274 |
pcie_cap_slot_event(PCI_DEVICE(hotplug_dev), PCI_EXP_HP_EV_PDC);
|
260 |
275 |
}
|
261 |
276 |
|
262 |
277 |
/* pci express slot for pci express root/downstream port
|
... | ... | |
305 |
320 |
|
306 |
321 |
dev->exp.hpev_notified = false;
|
307 |
322 |
|
308 |
|
pci_bus_hotplug(pci_bridge_get_sec_bus(PCI_BRIDGE(dev)),
|
309 |
|
pcie_cap_slot_hotplug, &dev->qdev);
|
|
323 |
qbus_set_hotplug_handler(BUS(pci_bridge_get_sec_bus(PCI_BRIDGE(dev))),
|
|
324 |
DEVICE(dev), NULL);
|
310 |
325 |
}
|
311 |
326 |
|
312 |
327 |
void pcie_cap_slot_reset(PCIDevice *dev)
|