aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/pci/controller/pci-hyperv.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-06 11:01:58 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-06 11:01:58 -0700
commit3925c3bbdf886f1ddf64461b9b380e1bb36f90c1 (patch)
tree99ebd7c46d46893057be0e5b16ea2bb356a1303b /drivers/pci/controller/pci-hyperv.c
parenthpfs: fix warning due to superfluous semicolon (diff)
parentMerge branch 'remotes/lorenzo/pci/vmd' (diff)
downloadwireguard-linux-3925c3bbdf886f1ddf64461b9b380e1bb36f90c1.tar.xz
wireguard-linux-3925c3bbdf886f1ddf64461b9b380e1bb36f90c1.zip
Merge tag 'pci-v5.8-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI updates from Bjorn Helgaas: "Enumeration: - Program MPS for RCiEP devices (Ashok Raj) - Fix pci_register_host_bridge() device_register() error handling (Rob Herring) - Fix pci_host_bridge struct device release/free handling (Rob Herring) Resource management: - Allow resizing BARs for devices on root bus (Ard Biesheuvel) Power management: - Reduce Thunderbolt resume time by working around devices that don't support DLL Link Active reporting (Mika Westerberg) - Work around a Pericom USB controller OHCI/EHCI PME# defect (Kai-Heng Feng) Virtualization: - Add ACS quirk for Intel Root Complex Integrated Endpoints (Ashok Raj) - Avoid FLR for AMD Starship USB 3.0 (Kevin Buettner) - Avoid FLR for AMD Matisse HD Audio & USB 3.0 (Marcos Scriven) Error handling: - Use only _OSC (not HEST FIRMWARE_FIRST) to determine AER ownership (Alexandru Gagniuc, Kuppuswamy Sathyanarayanan) - Reduce verbosity by logging only ACPI_NOTIFY_DISCONNECT_RECOVER events (Kuppuswamy Sathyanarayanan) - Don't enable AER by default in Kconfig (Bjorn Helgaas) Peer-to-peer DMA: - Add AMD Zen Raven and Renoir Root Ports to whitelist (Alex Deucher) ASPM: - Allow ASPM on links to PCIe-to-PCI/PCI-X Bridges (Kai-Heng Feng) Endpoint framework: - Fix DMA channel release in test (Kunihiko Hayashi) - Add page size as argument to pci_epc_mem_init() (Lad Prabhakar) - Add support to handle multiple base for mapping outbound memory (Lad Prabhakar) Generic host bridge driver: - Support building as module (Rob Herring) - Eliminate pci_host_common_probe wrappers (Rob Herring) Amlogic Meson PCIe controller driver: - Don't use FAST_LINK_MODE to set up link (Marc Zyngier) Broadcom STB PCIe controller driver: - Disable ASPM L0s if 'aspm-no-l0s' in DT (Jim Quinlan) - Fix clk_put() error (Jim Quinlan) - Fix window register offset (Jim Quinlan) - Assert fundamental reset on initialization (Nicolas Saenz Julienne) - Add notify xHCI reset property (Nicolas Saenz Julienne) - Add init routine for Raspberry Pi 4 VL805 USB controller (Nicolas Saenz Julienne) - Sync with Raspberry Pi 4 firmware for VL805 initialization (Nicolas Saenz Julienne) Cadence PCIe controller driver: - Remove "cdns,max-outbound-regions" DT property (replaced by "ranges") (Kishon Vijay Abraham I) - Read 32-bit (not 16-bit) Vendor ID/Device ID property from DT (Kishon Vijay Abraham I) Marvell Aardvark PCIe controller driver: - Improve link training (Marek Behún) - Add PHY support (Marek Behún) - Add "phys", "max-link-speed", "reset-gpios" to dt-binding (Marek Behún) - Train link immediately after enabling training to work around detection issues with some cards (Pali Rohár) - Issue PERST via GPIO to work around detection issues (Pali Rohár) - Don't blindly enable ASPM L0s (Pali Rohár) - Replace custom macros by standard linux/pci_regs.h macros (Pali Rohár) Microsoft Hyper-V host bridge driver: - Fix probe failure path to release resource (Wei Hu) - Retry PCI bus D0 entry on invalid device state for kdump (Wei Hu) Renesas R-Car PCIe controller driver: - Fix incorrect programming of OB windows (Andrew Murray) - Add suspend/resume (Kazufumi Ikeda) - Rename pcie-rcar.c to pcie-rcar-host.c (Lad Prabhakar) - Add endpoint controller driver (Lad Prabhakar) - Fix PCIEPAMR mask calculation (Lad Prabhakar) - Add r8a77961 to DT binding (Yoshihiro Shimoda) Socionext UniPhier Pro5 controller driver: - Add endpoint controller driver (Kunihiko Hayashi) Synopsys DesignWare PCIe controller driver: - Program outbound ATU upper limit register (Alan Mikhak) - Fix inner MSI IRQ domain registration (Marc Zyngier) Miscellaneous: - Check for platform_get_irq() failure consistently (negative return means failure) (Aman Sharma) - Fix several runtime PM get/put imbalances (Dinghao Liu) - Use flexible-array and struct_size() helpers for code cleanup (Gustavo A. R. Silva) - Update & fix issues in bridge emulation of PCIe registers (Jon Derrick) - Add macros for bridge window names (PCI_BRIDGE_IO_WINDOW, etc) (Krzysztof Wilczyński) - Work around Intel PCH MROMs that have invalid BARs (Xiaochun Lee)" * tag 'pci-v5.8-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (100 commits) PCI: uniphier: Add Socionext UniPhier Pro5 PCIe endpoint controller driver PCI: Add ACS quirk for Intel Root Complex Integrated Endpoints PCI/DPC: Print IRQ number used by port PCI/AER: Use "aer" variable for capability offset PCI/AER: Remove redundant dev->aer_cap checks PCI/AER: Remove redundant pci_is_pcie() checks PCI/AER: Remove HEST/FIRMWARE_FIRST parsing for AER ownership PCI: tegra: Fix runtime PM imbalance on error PCI: vmd: Filter resource type bits from shadow register PCI: tegra194: Fix runtime PM imbalance on error dt-bindings: PCI: Add UniPhier PCIe endpoint controller description PCI: hv: Use struct_size() helper PCI: Rename _DSM constants to align with spec PCI: Avoid FLR for AMD Starship USB 3.0 PCI: Avoid FLR for AMD Matisse HD Audio & USB 3.0 x86/PCI: Drop unused xen_register_pirq() gsi_override parameter PCI: dwc: Use private data pointer of "struct irq_domain" to get pcie_port PCI: amlogic: meson: Don't use FAST_LINK_MODE to set up link PCI: dwc: Fix inner MSI IRQ domain registration PCI: dwc: pci-dra7xx: Use devm_platform_ioremap_resource_byname() ...
Diffstat (limited to 'drivers/pci/controller/pci-hyperv.c')
-rw-r--r--drivers/pci/controller/pci-hyperv.c82
1 files changed, 62 insertions, 20 deletions
diff --git a/drivers/pci/controller/pci-hyperv.c b/drivers/pci/controller/pci-hyperv.c
index 222ff5639ebe..bf40ff09c99d 100644
--- a/drivers/pci/controller/pci-hyperv.c
+++ b/drivers/pci/controller/pci-hyperv.c
@@ -480,6 +480,9 @@ struct hv_pcibus_device {
struct workqueue_struct *wq;
+ /* Highest slot of child device with resources allocated */
+ int wslot_res_allocated;
+
/* hypercall arg, must not cross page boundary */
struct hv_retarget_device_interrupt retarget_msi_interrupt_params;
@@ -2210,10 +2213,8 @@ static void hv_pci_devices_present(struct hv_pcibus_device *hbus,
struct hv_dr_state *dr;
int i;
- dr = kzalloc(offsetof(struct hv_dr_state, func) +
- (sizeof(struct hv_pcidev_description) *
- (relations->device_count)), GFP_NOWAIT);
-
+ dr = kzalloc(struct_size(dr, func, relations->device_count),
+ GFP_NOWAIT);
if (!dr)
return;
@@ -2247,10 +2248,8 @@ static void hv_pci_devices_present2(struct hv_pcibus_device *hbus,
struct hv_dr_state *dr;
int i;
- dr = kzalloc(offsetof(struct hv_dr_state, func) +
- (sizeof(struct hv_pcidev_description) *
- (relations->device_count)), GFP_NOWAIT);
-
+ dr = kzalloc(struct_size(dr, func, relations->device_count),
+ GFP_NOWAIT);
if (!dr)
return;
@@ -2444,9 +2443,8 @@ static void hv_pci_onchannelcallback(void *context)
bus_rel = (struct pci_bus_relations *)buffer;
if (bytes_recvd <
- offsetof(struct pci_bus_relations, func) +
- (sizeof(struct pci_function_description) *
- (bus_rel->device_count))) {
+ struct_size(bus_rel, func,
+ bus_rel->device_count)) {
dev_err(&hbus->hdev->device,
"bus relations too small\n");
break;
@@ -2459,9 +2457,8 @@ static void hv_pci_onchannelcallback(void *context)
bus_rel2 = (struct pci_bus_relations2 *)buffer;
if (bytes_recvd <
- offsetof(struct pci_bus_relations2, func) +
- (sizeof(struct pci_function_description2) *
- (bus_rel2->device_count))) {
+ struct_size(bus_rel2, func,
+ bus_rel2->device_count)) {
dev_err(&hbus->hdev->device,
"bus relations v2 too small\n");
break;
@@ -2748,6 +2745,8 @@ static void hv_free_config_window(struct hv_pcibus_device *hbus)
vmbus_free_mmio(hbus->mem_config->start, PCI_CONFIG_MMIO_LENGTH);
}
+static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs);
+
/**
* hv_pci_enter_d0() - Bring the "bus" into the D0 power state
* @hdev: VMBus's tracking struct for this root PCI bus
@@ -2760,8 +2759,10 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
struct pci_bus_d0_entry *d0_entry;
struct hv_pci_compl comp_pkt;
struct pci_packet *pkt;
+ bool retry = true;
int ret;
+enter_d0_retry:
/*
* Tell the host that the bus is ready to use, and moved into the
* powered-on state. This includes telling the host which region
@@ -2788,6 +2789,38 @@ static int hv_pci_enter_d0(struct hv_device *hdev)
if (ret)
goto exit;
+ /*
+ * In certain case (Kdump) the pci device of interest was
+ * not cleanly shut down and resource is still held on host
+ * side, the host could return invalid device status.
+ * We need to explicitly request host to release the resource
+ * and try to enter D0 again.
+ */
+ if (comp_pkt.completion_status < 0 && retry) {
+ retry = false;
+
+ dev_err(&hdev->device, "Retrying D0 Entry\n");
+
+ /*
+ * Hv_pci_bus_exit() calls hv_send_resource_released()
+ * to free up resources of its child devices.
+ * In the kdump kernel we need to set the
+ * wslot_res_allocated to 255 so it scans all child
+ * devices to release resources allocated in the
+ * normal kernel before panic happened.
+ */
+ hbus->wslot_res_allocated = 255;
+
+ ret = hv_pci_bus_exit(hdev, true);
+
+ if (ret == 0) {
+ kfree(pkt);
+ goto enter_d0_retry;
+ }
+ dev_err(&hdev->device,
+ "Retrying D0 failed with ret %d\n", ret);
+ }
+
if (comp_pkt.completion_status < 0) {
dev_err(&hdev->device,
"PCI Pass-through VSP failed D0 Entry with status %x\n",
@@ -2859,7 +2892,7 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
struct hv_pci_dev *hpdev;
struct pci_packet *pkt;
size_t size_res;
- u32 wslot;
+ int wslot;
int ret;
size_res = (hbus->protocol_version < PCI_PROTOCOL_VERSION_1_2)
@@ -2912,6 +2945,8 @@ static int hv_send_resources_allocated(struct hv_device *hdev)
comp_pkt.completion_status);
break;
}
+
+ hbus->wslot_res_allocated = wslot;
}
kfree(pkt);
@@ -2930,10 +2965,10 @@ static int hv_send_resources_released(struct hv_device *hdev)
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
struct pci_child_message pkt;
struct hv_pci_dev *hpdev;
- u32 wslot;
+ int wslot;
int ret;
- for (wslot = 0; wslot < 256; wslot++) {
+ for (wslot = hbus->wslot_res_allocated; wslot >= 0; wslot--) {
hpdev = get_pcichild_wslot(hbus, wslot);
if (!hpdev)
continue;
@@ -2948,8 +2983,12 @@ static int hv_send_resources_released(struct hv_device *hdev)
VM_PKT_DATA_INBAND, 0);
if (ret)
return ret;
+
+ hbus->wslot_res_allocated = wslot - 1;
}
+ hbus->wslot_res_allocated = -1;
+
return 0;
}
@@ -3049,6 +3088,7 @@ static int hv_pci_probe(struct hv_device *hdev,
if (!hbus)
return -ENOMEM;
hbus->state = hv_pcibus_init;
+ hbus->wslot_res_allocated = -1;
/*
* The PCI bus "domain" is what is called "segment" in ACPI and other
@@ -3148,7 +3188,7 @@ static int hv_pci_probe(struct hv_device *hdev,
ret = hv_pci_allocate_bridge_windows(hbus);
if (ret)
- goto free_irq_domain;
+ goto exit_d0;
ret = hv_send_resources_allocated(hdev);
if (ret)
@@ -3166,6 +3206,8 @@ static int hv_pci_probe(struct hv_device *hdev,
free_windows:
hv_pci_free_bridge_windows(hbus);
+exit_d0:
+ (void) hv_pci_bus_exit(hdev, true);
free_irq_domain:
irq_domain_remove(hbus->irq_domain);
free_fwnode:
@@ -3185,7 +3227,7 @@ free_bus:
return ret;
}
-static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
+static int hv_pci_bus_exit(struct hv_device *hdev, bool keep_devs)
{
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
struct {
@@ -3203,7 +3245,7 @@ static int hv_pci_bus_exit(struct hv_device *hdev, bool hibernating)
if (hdev->channel->rescind)
return 0;
- if (!hibernating) {
+ if (!keep_devs) {
/* Delete any children which might still exist. */
dr = kzalloc(sizeof(*dr), GFP_KERNEL);
if (dr && hv_pci_start_relations_work(hbus, dr))