|
|
60061b |
From c655f89956c69dc4bb3c3c74515c6c04bd0195bb Mon Sep 17 00:00:00 2001
|
|
|
60061b |
From: Igor Mammedov <imammedo@redhat.com>
|
|
|
60061b |
Date: Tue, 1 Mar 2022 10:11:59 -0500
|
|
|
60061b |
Subject: [PATCH 6/6] acpi: pcihp: pcie: set power on cap on parent slot
|
|
|
60061b |
|
|
|
60061b |
RH-Author: Igor Mammedov <imammedo@redhat.com>
|
|
|
60061b |
RH-MergeRequest: 125: RHEL-8.6 Fix broken PCIe device after migration
|
|
|
60061b |
RH-Commit: [2/2] effbd75b9d495c88dd4d910b547154849fb1e821
|
|
|
60061b |
RH-Bugzilla: 2054597
|
|
|
60061b |
RH-Acked-by: Jon Maloy <jmaloy@redhat.com>
|
|
|
60061b |
RH-Acked-by: Gerd Hoffmann <kraxel@redhat.com>
|
|
|
60061b |
RH-Acked-by: MST <None>
|
|
|
60061b |
|
|
|
60061b |
on creation a PCIDevice has power turned on at the end of pci_qdev_realize()
|
|
|
60061b |
however later on if PCIe slot isn't populated with any children
|
|
|
60061b |
it's power is turned off. It's fine if native hotplug is used
|
|
|
60061b |
as plug callback will power slot on among other things.
|
|
|
60061b |
However when ACPI hotplug is enabled it replaces native PCIe plug
|
|
|
60061b |
callbacks with ACPI specific ones (acpi_pcihp_device_*plug_cb) and
|
|
|
60061b |
as result slot stays powered off. It works fine as ACPI hotplug
|
|
|
60061b |
on guest side takes care of enumerating/initializing hotplugged
|
|
|
60061b |
device. But when later guest is migrated, call chain introduced by]
|
|
|
60061b |
commit d5daff7d312 (pcie: implement slot power control for pcie root ports)
|
|
|
60061b |
|
|
|
60061b |
pcie_cap_slot_post_load()
|
|
|
60061b |
-> pcie_cap_update_power()
|
|
|
60061b |
-> pcie_set_power_device()
|
|
|
60061b |
-> pci_set_power()
|
|
|
60061b |
-> pci_update_mappings()
|
|
|
60061b |
|
|
|
60061b |
will disable earlier initialized BARs for the hotplugged device
|
|
|
60061b |
in powered off slot due to commit 23786d13441 (pci: implement power state)
|
|
|
60061b |
which disables BARs if power is off.
|
|
|
60061b |
|
|
|
60061b |
Fix it by setting PCI_EXP_SLTCTL_PCC to PCI_EXP_SLTCTL_PWR_ON
|
|
|
60061b |
on slot (root port/downstream port) at the time a device
|
|
|
60061b |
hotplugged into it. As result PCI_EXP_SLTCTL_PWR_ON is migrated
|
|
|
60061b |
to target and above call chain keeps device plugged into it
|
|
|
60061b |
powered on.
|
|
|
60061b |
|
|
|
60061b |
Fixes: d5daff7d312 ("pcie: implement slot power control for pcie root ports")
|
|
|
60061b |
Fixes: 23786d13441 ("pci: implement power state")
|
|
|
60061b |
Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=2053584
|
|
|
60061b |
Suggested-by: "Michael S. Tsirkin" <mst@redhat.com>
|
|
|
60061b |
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
|
|
60061b |
Message-Id: <20220301151200.3507298-3-imammedo@redhat.com>
|
|
|
60061b |
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
60061b |
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
|
|
|
60061b |
(cherry picked from commit 6b0969f1ec825984cd74619f0730be421b0c46fb)
|
|
|
60061b |
Signed-off-by: Igor Mammedov <imammedo@redhat.com>
|
|
|
60061b |
---
|
|
|
60061b |
hw/acpi/pcihp.c | 12 +++++++++++-
|
|
|
60061b |
hw/pci/pcie.c | 11 +++++++++++
|
|
|
60061b |
include/hw/pci/pcie.h | 1 +
|
|
|
60061b |
3 files changed, 23 insertions(+), 1 deletion(-)
|
|
|
60061b |
|
|
|
60061b |
diff --git a/hw/acpi/pcihp.c b/hw/acpi/pcihp.c
|
|
|
60061b |
index a5e182dd3a..be0e846b34 100644
|
|
|
60061b |
--- a/hw/acpi/pcihp.c
|
|
|
60061b |
+++ b/hw/acpi/pcihp.c
|
|
|
60061b |
@@ -32,6 +32,7 @@
|
|
|
60061b |
#include "hw/pci/pci_bridge.h"
|
|
|
60061b |
#include "hw/pci/pci_host.h"
|
|
|
60061b |
#include "hw/pci/pcie_port.h"
|
|
|
60061b |
+#include "hw/pci-bridge/xio3130_downstream.h"
|
|
|
60061b |
#include "hw/i386/acpi-build.h"
|
|
|
60061b |
#include "hw/acpi/acpi.h"
|
|
|
60061b |
#include "hw/pci/pci_bus.h"
|
|
|
60061b |
@@ -341,6 +342,8 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
|
|
|
60061b |
{
|
|
|
60061b |
PCIDevice *pdev = PCI_DEVICE(dev);
|
|
|
60061b |
int slot = PCI_SLOT(pdev->devfn);
|
|
|
60061b |
+ PCIDevice *bridge;
|
|
|
60061b |
+ PCIBus *bus;
|
|
|
60061b |
int bsel;
|
|
|
60061b |
|
|
|
60061b |
/* Don't send event when device is enabled during qemu machine creation:
|
|
|
60061b |
@@ -370,7 +373,14 @@ void acpi_pcihp_device_plug_cb(HotplugHandler *hotplug_dev, AcpiPciHpState *s,
|
|
|
60061b |
return;
|
|
|
60061b |
}
|
|
|
60061b |
|
|
|
60061b |
- bsel = acpi_pcihp_get_bsel(pci_get_bus(pdev));
|
|
|
60061b |
+ bus = pci_get_bus(pdev);
|
|
|
60061b |
+ bridge = pci_bridge_get_device(bus);
|
|
|
60061b |
+ if (object_dynamic_cast(OBJECT(bridge), TYPE_PCIE_ROOT_PORT) ||
|
|
|
60061b |
+ object_dynamic_cast(OBJECT(bridge), TYPE_XIO3130_DOWNSTREAM)) {
|
|
|
60061b |
+ pcie_cap_slot_enable_power(bridge);
|
|
|
60061b |
+ }
|
|
|
60061b |
+
|
|
|
60061b |
+ bsel = acpi_pcihp_get_bsel(bus);
|
|
|
60061b |
g_assert(bsel >= 0);
|
|
|
60061b |
s->acpi_pcihp_pci_status[bsel].up |= (1U << slot);
|
|
|
60061b |
acpi_send_event(DEVICE(hotplug_dev), ACPI_PCI_HOTPLUG_STATUS);
|
|
|
60061b |
diff --git a/hw/pci/pcie.c b/hw/pci/pcie.c
|
|
|
60061b |
index d7d73a31e4..996f0e24fe 100644
|
|
|
60061b |
--- a/hw/pci/pcie.c
|
|
|
60061b |
+++ b/hw/pci/pcie.c
|
|
|
60061b |
@@ -366,6 +366,17 @@ static void hotplug_event_clear(PCIDevice *dev)
|
|
|
60061b |
}
|
|
|
60061b |
}
|
|
|
60061b |
|
|
|
60061b |
+void pcie_cap_slot_enable_power(PCIDevice *dev)
|
|
|
60061b |
+{
|
|
|
60061b |
+ uint8_t *exp_cap = dev->config + dev->exp.exp_cap;
|
|
|
60061b |
+ uint32_t sltcap = pci_get_long(exp_cap + PCI_EXP_SLTCAP);
|
|
|
60061b |
+
|
|
|
60061b |
+ if (sltcap & PCI_EXP_SLTCAP_PCP) {
|
|
|
60061b |
+ pci_set_word_by_mask(exp_cap + PCI_EXP_SLTCTL,
|
|
|
60061b |
+ PCI_EXP_SLTCTL_PCC, PCI_EXP_SLTCTL_PWR_ON);
|
|
|
60061b |
+ }
|
|
|
60061b |
+}
|
|
|
60061b |
+
|
|
|
60061b |
static void pcie_set_power_device(PCIBus *bus, PCIDevice *dev, void *opaque)
|
|
|
60061b |
{
|
|
|
60061b |
bool *power = opaque;
|
|
|
60061b |
diff --git a/include/hw/pci/pcie.h b/include/hw/pci/pcie.h
|
|
|
60061b |
index 6063bee0ec..c27368d077 100644
|
|
|
60061b |
--- a/include/hw/pci/pcie.h
|
|
|
60061b |
+++ b/include/hw/pci/pcie.h
|
|
|
60061b |
@@ -112,6 +112,7 @@ void pcie_cap_slot_write_config(PCIDevice *dev,
|
|
|
60061b |
uint32_t addr, uint32_t val, int len);
|
|
|
60061b |
int pcie_cap_slot_post_load(void *opaque, int version_id);
|
|
|
60061b |
void pcie_cap_slot_push_attention_button(PCIDevice *dev);
|
|
|
60061b |
+void pcie_cap_slot_enable_power(PCIDevice *dev);
|
|
|
60061b |
|
|
|
60061b |
void pcie_cap_root_init(PCIDevice *dev);
|
|
|
60061b |
void pcie_cap_root_reset(PCIDevice *dev);
|
|
|
60061b |
--
|
|
|
60061b |
2.27.0
|
|
|
60061b |
|