Skip to content

Commit c81992e

Browse files
whu2014Lorenzo Pieralisi
authored andcommitted
PCI: hv: Retry PCI bus D0 entry on invalid device state
When kdump is triggered, some PCI devices may have not been shut down cleanly before the kdump kernel starts. This causes the initial attempt to enter D0 state in the kdump kernel to fail with invalid device state returned from Hyper-V host. When this happens, explicitly call hv_pci_bus_exit() and retry to enter the D0 state. Link: https://lore.kernel.org/r/20200507050300.10974-1-weh@microsoft.com Signed-off-by: Wei Hu <weh@microsoft.com> [lorenzo.pieralisi@arm.com: commit log] Signed-off-by: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com> Reviewed-by: Michael Kelley <mikelley@microsoft.com>
1 parent 83cc350 commit c81992e

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

drivers/pci/controller/pci-hyperv.c

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2739,6 +2739,8 @@ static void hv_free_config_window(struct hv_pcibus_device *hbus)
27392739
vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
27402740
}
27412741

2742+
static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs);
2743+
27422744
/**
27432745
* hv_pci_enter_d0() - Bring the "bus" into the D0 power state
27442746
* @hdev: VMBus's tracking struct for this root PCI bus
@@ -2751,8 +2753,10 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
27512753
struct pci_bus_d0_entry *d0_entry;
27522754
struct hv_pci_compl comp_pkt;
27532755
struct pci_packet *pkt;
2756+
bool retry = true;
27542757
int ret;
27552758

2759+
enter_d0_retry:
27562760
/*
27572761
* Tell the host that the bus is ready to use, and moved into the
27582762
* powered-on state. This includes telling the host which region
@@ -2779,6 +2783,38 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
27792783
if (ret)
27802784
goto exit;
27812785

2786+
/*
2787+
* In certain case (Kdump) the pci device of interest was
2788+
* not cleanly shut down and resource is still held on host
2789+
* side, the host could return invalid device status.
2790+
* We need to explicitly request host to release the resource
2791+
* and try to enter D0 again.
2792+
*/
2793+
if (comp_pkt.completion_status < 0 && retry) {
2794+
retry = false;
2795+
2796+
dev_err(&hdev->device, "Retrying D0 Entry\n");
2797+
2798+
/*
2799+
* Hv_pci_bus_exit() calls hv_send_resource_released()
2800+
* to free up resources of its child devices.
2801+
* In the kdump kernel we need to set the
2802+
* wslot_res_allocated to 255 so it scans all child
2803+
* devices to release resources allocated in the
2804+
* normal kernel before panic happened.
2805+
*/
2806+
hbus->wslot_res_allocated = 255;
2807+
2808+
ret = hv_pci_bus_exit(hdev, true);
2809+
2810+
if (ret == 0) {
2811+
kfree(pkt);
2812+
goto enter_d0_retry;
2813+
}
2814+
dev_err(&hdev->device,
2815+
"Retrying D0 failed with ret %d\n", ret);
2816+
}
2817+
27822818
if (comp_pkt.completion_status < 0) {
27832819
dev_err(&hdev->device,
27842820
"PCI Pass-through VSP failed D0 Entry with status %x\n",
@@ -3185,7 +3221,7 @@ static int hv_pci_probe(struct hv_device *hdev,
31853221
return ret;
31863222
}
31873223

3188-
static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
3224+
static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
31893225
{
31903226
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
31913227
struct {
@@ -3203,7 +3239,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
32033239
if (hdev->channel->rescind)
32043240
return 0;
32053241

3206-
if (!hibernating) {
3242+
if (!keep_devs) {
32073243
/* Delete any children which might still exist. */
32083244
dr = kzalloc(sizeof(*dr), GFP_KERNEL);
32093245
if (dr && hv_pci_start_relations_work(hbus, dr))

0 commit comments

Comments
 (0)