Merge branch 'pci/host-hv' into next
* pci/host-hv: PCI: hv: Allocate physically contiguous hypercall params buffer PCI: hv: Delete the device earlier from hbus->children for hot-remove PCI: hv: Fix hv_pci_remove() for hot-remove PCI: hv: Use the correct buffer size in new_pcichild_device() PCI: hv: Make unnecessarily global IRQ masking functions static
This commit is contained in:
commit
b0b8975906
|
@ -378,6 +378,8 @@ struct hv_pcibus_device {
|
||||||
struct msi_domain_info msi_info;
|
struct msi_domain_info msi_info;
|
||||||
struct msi_controller msi_chip;
|
struct msi_controller msi_chip;
|
||||||
struct irq_domain *irq_domain;
|
struct irq_domain *irq_domain;
|
||||||
|
struct retarget_msi_interrupt retarget_msi_interrupt_params;
|
||||||
|
spinlock_t retarget_msi_interrupt_lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -755,7 +757,7 @@ static int hv_set_affinity(struct irq_data *data, const struct cpumask *dest,
|
||||||
return parent->chip->irq_set_affinity(parent, dest, force);
|
return parent->chip->irq_set_affinity(parent, dest, force);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hv_irq_mask(struct irq_data *data)
|
static void hv_irq_mask(struct irq_data *data)
|
||||||
{
|
{
|
||||||
pci_msi_mask_irq(data);
|
pci_msi_mask_irq(data);
|
||||||
}
|
}
|
||||||
|
@ -770,38 +772,44 @@ void hv_irq_mask(struct irq_data *data)
|
||||||
* is built out of this PCI bus's instance GUID and the function
|
* is built out of this PCI bus's instance GUID and the function
|
||||||
* number of the device.
|
* number of the device.
|
||||||
*/
|
*/
|
||||||
void hv_irq_unmask(struct irq_data *data)
|
static void hv_irq_unmask(struct irq_data *data)
|
||||||
{
|
{
|
||||||
struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
|
struct msi_desc *msi_desc = irq_data_get_msi_desc(data);
|
||||||
struct irq_cfg *cfg = irqd_cfg(data);
|
struct irq_cfg *cfg = irqd_cfg(data);
|
||||||
struct retarget_msi_interrupt params;
|
struct retarget_msi_interrupt *params;
|
||||||
struct hv_pcibus_device *hbus;
|
struct hv_pcibus_device *hbus;
|
||||||
struct cpumask *dest;
|
struct cpumask *dest;
|
||||||
struct pci_bus *pbus;
|
struct pci_bus *pbus;
|
||||||
struct pci_dev *pdev;
|
struct pci_dev *pdev;
|
||||||
int cpu;
|
int cpu;
|
||||||
|
unsigned long flags;
|
||||||
|
|
||||||
dest = irq_data_get_affinity_mask(data);
|
dest = irq_data_get_affinity_mask(data);
|
||||||
pdev = msi_desc_to_pci_dev(msi_desc);
|
pdev = msi_desc_to_pci_dev(msi_desc);
|
||||||
pbus = pdev->bus;
|
pbus = pdev->bus;
|
||||||
hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
|
hbus = container_of(pbus->sysdata, struct hv_pcibus_device, sysdata);
|
||||||
|
|
||||||
memset(¶ms, 0, sizeof(params));
|
spin_lock_irqsave(&hbus->retarget_msi_interrupt_lock, flags);
|
||||||
params.partition_id = HV_PARTITION_ID_SELF;
|
|
||||||
params.source = 1; /* MSI(-X) */
|
params = &hbus->retarget_msi_interrupt_params;
|
||||||
params.address = msi_desc->msg.address_lo;
|
memset(params, 0, sizeof(*params));
|
||||||
params.data = msi_desc->msg.data;
|
params->partition_id = HV_PARTITION_ID_SELF;
|
||||||
params.device_id = (hbus->hdev->dev_instance.b[5] << 24) |
|
params->source = 1; /* MSI(-X) */
|
||||||
|
params->address = msi_desc->msg.address_lo;
|
||||||
|
params->data = msi_desc->msg.data;
|
||||||
|
params->device_id = (hbus->hdev->dev_instance.b[5] << 24) |
|
||||||
(hbus->hdev->dev_instance.b[4] << 16) |
|
(hbus->hdev->dev_instance.b[4] << 16) |
|
||||||
(hbus->hdev->dev_instance.b[7] << 8) |
|
(hbus->hdev->dev_instance.b[7] << 8) |
|
||||||
(hbus->hdev->dev_instance.b[6] & 0xf8) |
|
(hbus->hdev->dev_instance.b[6] & 0xf8) |
|
||||||
PCI_FUNC(pdev->devfn);
|
PCI_FUNC(pdev->devfn);
|
||||||
params.vector = cfg->vector;
|
params->vector = cfg->vector;
|
||||||
|
|
||||||
for_each_cpu_and(cpu, dest, cpu_online_mask)
|
for_each_cpu_and(cpu, dest, cpu_online_mask)
|
||||||
params.vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu));
|
params->vp_mask |= (1ULL << vmbus_cpu_number_to_vp_number(cpu));
|
||||||
|
|
||||||
hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, ¶ms, NULL);
|
hv_do_hypercall(HVCALL_RETARGET_INTERRUPT, params, NULL);
|
||||||
|
|
||||||
|
spin_unlock_irqrestore(&hbus->retarget_msi_interrupt_lock, flags);
|
||||||
|
|
||||||
pci_msi_unmask_irq(data);
|
pci_msi_unmask_irq(data);
|
||||||
}
|
}
|
||||||
|
@ -1271,9 +1279,9 @@ static struct hv_pci_dev *new_pcichild_device(struct hv_pcibus_device *hbus,
|
||||||
struct hv_pci_dev *hpdev;
|
struct hv_pci_dev *hpdev;
|
||||||
struct pci_child_message *res_req;
|
struct pci_child_message *res_req;
|
||||||
struct q_res_req_compl comp_pkt;
|
struct q_res_req_compl comp_pkt;
|
||||||
union {
|
struct {
|
||||||
struct pci_packet init_packet;
|
struct pci_packet init_packet;
|
||||||
u8 buffer[0x100];
|
u8 buffer[sizeof(struct pci_child_message)];
|
||||||
} pkt;
|
} pkt;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -1582,6 +1590,10 @@ static void hv_eject_device_work(struct work_struct *work)
|
||||||
pci_dev_put(pdev);
|
pci_dev_put(pdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
|
||||||
|
list_del(&hpdev->list_entry);
|
||||||
|
spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
|
||||||
|
|
||||||
memset(&ctxt, 0, sizeof(ctxt));
|
memset(&ctxt, 0, sizeof(ctxt));
|
||||||
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
|
ejct_pkt = (struct pci_eject_response *)&ctxt.pkt.message;
|
||||||
ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
|
ejct_pkt->message_type.type = PCI_EJECTION_COMPLETE;
|
||||||
|
@ -1590,10 +1602,6 @@ static void hv_eject_device_work(struct work_struct *work)
|
||||||
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
|
sizeof(*ejct_pkt), (unsigned long)&ctxt.pkt,
|
||||||
VM_PKT_DATA_INBAND, 0);
|
VM_PKT_DATA_INBAND, 0);
|
||||||
|
|
||||||
spin_lock_irqsave(&hpdev->hbus->device_list_lock, flags);
|
|
||||||
list_del(&hpdev->list_entry);
|
|
||||||
spin_unlock_irqrestore(&hpdev->hbus->device_list_lock, flags);
|
|
||||||
|
|
||||||
put_pcichild(hpdev, hv_pcidev_ref_childlist);
|
put_pcichild(hpdev, hv_pcidev_ref_childlist);
|
||||||
put_pcichild(hpdev, hv_pcidev_ref_pnp);
|
put_pcichild(hpdev, hv_pcidev_ref_pnp);
|
||||||
put_hvpcibus(hpdev->hbus);
|
put_hvpcibus(hpdev->hbus);
|
||||||
|
@ -2186,6 +2194,7 @@ static int hv_pci_probe(struct hv_device *hdev,
|
||||||
INIT_LIST_HEAD(&hbus->resources_for_children);
|
INIT_LIST_HEAD(&hbus->resources_for_children);
|
||||||
spin_lock_init(&hbus->config_lock);
|
spin_lock_init(&hbus->config_lock);
|
||||||
spin_lock_init(&hbus->device_list_lock);
|
spin_lock_init(&hbus->device_list_lock);
|
||||||
|
spin_lock_init(&hbus->retarget_msi_interrupt_lock);
|
||||||
sema_init(&hbus->enum_sem, 1);
|
sema_init(&hbus->enum_sem, 1);
|
||||||
init_completion(&hbus->remove_event);
|
init_completion(&hbus->remove_event);
|
||||||
|
|
||||||
|
@ -2266,24 +2275,32 @@ free_bus:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
static void hv_pci_bus_exit(struct hv_device *hdev)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
int ret;
|
struct hv_pcibus_device *hbus = hv_get_drvdata(hdev);
|
||||||
struct hv_pcibus_device *hbus;
|
struct {
|
||||||
union {
|
|
||||||
struct pci_packet teardown_packet;
|
struct pci_packet teardown_packet;
|
||||||
u8 buffer[0x100];
|
u8 buffer[sizeof(struct pci_message)];
|
||||||
} pkt;
|
} pkt;
|
||||||
struct pci_bus_relations relations;
|
struct pci_bus_relations relations;
|
||||||
struct hv_pci_compl comp_pkt;
|
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));
|
memset(&pkt.teardown_packet, 0, sizeof(pkt.teardown_packet));
|
||||||
init_completion(&comp_pkt.host_event);
|
init_completion(&comp_pkt.host_event);
|
||||||
|
@ -2298,7 +2315,19 @@ static int hv_pci_remove(struct hv_device *hdev)
|
||||||
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
VMBUS_DATA_PACKET_FLAG_COMPLETION_REQUESTED);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
wait_for_completion_timeout(&comp_pkt.host_event, 10 * HZ);
|
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) {
|
if (hbus->state == hv_pcibus_installed) {
|
||||||
/* Remove the bus from PCI's point of view. */
|
/* Remove the bus from PCI's point of view. */
|
||||||
pci_lock_rescan_remove();
|
pci_lock_rescan_remove();
|
||||||
|
@ -2307,17 +2336,10 @@ static int hv_pci_remove(struct hv_device *hdev)
|
||||||
pci_unlock_rescan_remove();
|
pci_unlock_rescan_remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = hv_send_resources_released(hdev);
|
hv_pci_bus_exit(hdev);
|
||||||
if (ret)
|
|
||||||
dev_err(&hdev->device,
|
|
||||||
"Couldn't send resources released packet(s)\n");
|
|
||||||
|
|
||||||
vmbus_close(hdev->channel);
|
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);
|
iounmap(hbus->cfg_addr);
|
||||||
hv_free_config_window(hbus);
|
hv_free_config_window(hbus);
|
||||||
pci_free_resource_list(&hbus->resources_for_children);
|
pci_free_resource_list(&hbus->resources_for_children);
|
||||||
|
|
Loading…
Reference in New Issue