Commit 17978524 authored by Dexuan Cui's avatar Dexuan Cui Committed by Bjorn Helgaas
Browse files

PCI: hv: Fix hv_pci_remove() for hot-remove



1. We don't really need such a big on-stack buffer when sending the
teardown_packet: vmbus_sendpacket() here only uses sizeof(struct
pci_message).

2. In the hot-remove case (PCI_EJECT), after we send PCI_EJECTION_COMPLETE
to the host, the host will send a RESCIND_CHANNEL message to us and the
host won't access the per-channel ringbuffer any longer, so we needn't send
PCI_RESOURCES_RELEASED/PCI_BUS_D0EXIT to the host, and we shouldn't expect
the host's completion message of PCI_BUS_D0EXIT, which will never come.

3. We should send PCI_BUS_D0EXIT after hv_send_resources_released().

Signed-off-by: default avatarDexuan Cui <decui@microsoft.com>
Signed-off-by: default avatarBjorn Helgaas <bhelgaas@google.com>
Reviewed-by: default avatarJake Oshins <jakeo@microsoft.com>
Acked-by: default avatarK. Y. Srinivasan <kys@microsoft.com>
CC: Haiyang Zhang <haiyangz@microsoft.com>
CC: Vitaly Kuznetsov <vkuznets@redhat.com>
parent 8286e96d
Loading
Loading
Loading
Loading
+33 −20
Original line number Diff line number Diff line
@@ -2266,24 +2266,32 @@ free_bus:
	return ret;
}

/**
 * hv_pci_remove() - Remove routine for this VMBus channel
 * @hdev:	VMBus's tracking struct for this root PCI bus
 *
 * Return: 0 on success, -errno on failure
 */
static int hv_pci_remove(struct hv_device *hdev)
static void hv_pci_bus_exit(struct hv_device *hdev)
{
	int ret;
	struct hv_pcibus_device *hbus;
	union {
	struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
	struct {
		struct pci_packet teardown_packet;
		u8 buffer[0x100];
		u8 buffer[sizeof(struct pci_message)];
	} pkt;
	struct pci_bus_relations relations;
	struct hv_pci_compl comp_pkt;
	int ret;

	hbus = hv_get_drvdata(hdev);
	/*
	 * After the host sends the RESCIND_CHANNEL message, it doesn't
	 * access the per-channel ringbuffer any longer.
	 */
	if (hdev->channel->rescind)
		return;

	/* Delete any children which might still exist. */
	memset(&relations, 0, sizeof(relations));
	hv_pci_devices_present(hbus, &relations);

	ret = hv_send_resources_released(hdev);
	if (ret)
		dev_err(&hdev->device,
			"Couldn't send resources released packet(s)\n");

	memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
	init_completion(&comp_pkt.host_event);
@@ -2298,7 +2306,19 @@ static int hv_pci_remove(struct hv_device *hdev)
			       VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
	if (!ret)
		wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ);
}

/**
 * hv_pci_remove() - Remove routine for this VMBus channel
 * @hdev:	VMBus's tracking struct for this root PCI bus
 *
 * Return: 0 on success, -errno on failure
 */
static int hv_pci_remove(struct hv_device *hdev)
{
	struct hv_pcibus_device *hbus;

	hbus = hv_get_drvdata(hdev);
	if (hbus->state == hv_pcibus_installed) {
		/* Remove the bus from PCI's point of view. */
		pci_lock_rescan_remove();
@@ -2307,17 +2327,10 @@ static int hv_pci_remove(struct hv_device *hdev)
		pci_unlock_rescan_remove();
	}

	ret = hv_send_resources_released(hdev);
	if (ret)
		dev_err(&hdev->device,
			"Couldn't send resources released packet(s)\n");
	hv_pci_bus_exit(hdev);

	vmbus_close(hdev->channel);

	/* Delete any children which might still exist. */
	memset(&relations, 0, sizeof(relations));
	hv_pci_devices_present(hbus, &relations);

	iounmap(hbus->cfg_addr);
	hv_free_config_window(hbus);
	pci_free_resource_list(&hbus->resources_for_children);