* with this program; if not, see <http://www.gnu.org/licenses/>.
*/
-#include "sysemu.h"
-#include "range.h"
+#include "qemu-common.h"
#include "pci_bridge.h"
#include "pcie.h"
#include "msix.h"
* The Port may optionally send an MSI when there are hot-plug events that
* occur while interrupt generation is disabled, and interrupt generation is
* subsequently enabled. */
- if (!pci_msi_enabled(dev)) {
+ if (msix_enabled(dev)) {
+ msix_notify(dev, pcie_cap_flags_get_vector(dev));
+ } else if (msi_enabled(dev)) {
+ msi_notify(dev, pcie_cap_flags_get_vector(dev));
+ } else {
qemu_set_irq(dev->irq[dev->exp.hpev_intx], dev->exp.hpev_notified);
- } else if (dev->exp.hpev_notified) {
- pci_msi_notify(dev, pcie_cap_flags_get_vector(dev));
+ }
+}
+
+static void hotplug_event_clear(PCIDevice *dev)
+{
+ hotplug_event_update_event_status(dev);
+ if (!msix_enabled(dev) && !msi_enabled(dev) && !dev->exp.hpev_notified) {
+ qemu_set_irq(dev->irq[dev->exp.hpev_intx], 0);
}
}
/*
- * A PCI Express Hot-Plug Event has occured, so update slot status register
+ * A PCI Express Hot-Plug Event has occurred, so update slot status register
* and notify OS of the event if necessary.
*
* 6.7.3 PCI Express Hot-Plug Events
}
static int pcie_cap_slot_hotplug(DeviceState *qdev,
- PCIDevice *pci_dev, int state)
+ PCIDevice *pci_dev, PCIHotplugState state)
{
PCIDevice *d = DO_UPCAST(PCIDevice, qdev, qdev);
uint8_t *exp_cap = d->config + d->exp.exp_cap;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
- if (!pci_dev->qdev.hotplugged) {
- assert(state); /* this case only happens at machine creation. */
+ /* Don't send event when device is enabled during qemu machine creation:
+ * it is present on boot, no hotplug event is necessary. We do send an
+ * event when the device is disabled later. */
+ if (state == PCI_COLDPLUG_ENABLED) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
return 0;
*/
assert(PCI_FUNC(pci_dev->devfn) == 0);
- if (state) {
+ if (state == PCI_HOTPLUG_ENABLED) {
pci_word_test_and_set_mask(exp_cap + PCI_EXP_SLTSTA,
PCI_EXP_SLTSTA_PDS);
pcie_cap_slot_event(d, PCI_EXP_HP_EV_PDC);
uint8_t *exp_cap = dev->config + pos;
uint16_t sltsta = pci_get_word(exp_cap + PCI_EXP_SLTSTA);
+ if (ranges_overlap(addr, len, pos + PCI_EXP_SLTSTA, 2)) {
+ hotplug_event_clear(dev);
+ }
+
if (!ranges_overlap(addr, len, pos + PCI_EXP_SLTCTL, 2)) {
return;
}
pci_set_word(dev->config + dev->exp.exp_cap + PCI_EXP_RTCTL, 0);
}
-/*
- * TODO: implement FLR:
- * Right now sets the bit which indicates FLR is supported.
- */
/* function level reset(FLR) */
void pcie_cap_flr_init(PCIDevice *dev)
{
uint32_t addr, uint32_t val, int len)
{
uint8_t *devctl = dev->config + dev->exp.exp_cap + PCI_EXP_DEVCTL;
- if (pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR)) {
- /* TODO: implement FLR */
+ if (pci_get_word(devctl) & PCI_EXP_DEVCTL_BCR_FLR) {
+ /* Clear PCI_EXP_DEVCTL_BCR_FLR after invoking the reset handler
+ so the handler can detect FLR by looking at this bit. */
+ pci_device_reset(dev);
+ pci_word_test_and_clear_mask(devctl, PCI_EXP_DEVCTL_BCR_FLR);
}
}