Ask the hypervisor to retarget interrupts to new guest cpu or vector upon guest irq migration. This happens in the irqfd update path.
Signed-off-by: Mukesh R <[email protected]> --- drivers/hv/mshv_eventfd.c | 78 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 76 insertions(+), 2 deletions(-) diff --git a/drivers/hv/mshv_eventfd.c b/drivers/hv/mshv_eventfd.c index 1f5c1e9ee9b7..c05201d857fd 100644 --- a/drivers/hv/mshv_eventfd.c +++ b/drivers/hv/mshv_eventfd.c @@ -192,6 +192,77 @@ static int mshv_map_device_interrupt(u64 ptid, union hv_device_id hv_devid, } +/* NOTE: caller does spin_lock_irq on pt_irqfds_lock, hence no disable here */ +static void mshv_do_guest_irq_retarget(u64 partid, struct mshv_irqfd *irqfd) +{ + int rc, var_size; + u64 status; + union hv_device_id hv_devid; + struct hv_input_get_vp_set_from_mda *mda_input; + union hv_output_get_vp_set_from_mda *mda_output; + struct hv_retarget_device_interrupt *remap_inp; + struct pci_dev *pdev; + struct irq_data *irqdata; + struct mshv_lapic_irq *lapic_irq = &irqfd->irqfd_lapic_irq; + struct hv_interrupt_entry *inte = NULL; + + if (!irqfd->irqfd_girq_ent.girq_entry_valid || + irqfd->irqfd_bypass_prod == NULL) + return; + + rc = mshv_parse_mshv_irqfd(irqfd, &pdev, &irqdata); + if (rc) + return; + + inte = irqdata->chip_data; + if (inte == NULL) + return; + + hv_devid.as_uint64 = hv_devid_from_pdev(pdev); + + + mda_input = *this_cpu_ptr(hyperv_pcpu_input_arg); + mda_output = *this_cpu_ptr(hyperv_pcpu_output_arg); + + rc = hv_vpset_from_hyp_disabled(mda_input, mda_output, lapic_irq, + partid); + if (rc) + return; + + remap_inp = *this_cpu_ptr(hyperv_pcpu_input_arg); + memset(remap_inp, 0, sizeof(*remap_inp)); + + rc = hv_copy_vpset(&remap_inp->int_target.vp_set, + &mda_output->target_vpset); + if (rc <= 0) { + pr_err("Hyper-V: ptid %lld - vpset copy failed (%d)\n", + partid, rc); + return; + } + + /* + * var-sized hcall: var-size starts after vp_mask (thus vp_set.format + * does not count, but vp_set.valid_bank_mask does). + */ + var_size = rc + 1; + + remap_inp->partition_id = partid; + remap_inp->device_id = hv_devid.as_uint64; + remap_inp->int_target.vector = lapic_irq->lapic_vector; + remap_inp->int_target.flags = HV_DEVICE_INTERRUPT_TARGET_PROCESSOR_SET; + + remap_inp->int_entry.source = inte->source; + remap_inp->int_entry.msi_entry.as_uint64 = inte->msi_entry.as_uint64; + + status = hv_do_rep_hypercall(HVCALL_RETARGET_INTERRUPT, 0, var_size, + remap_inp, NULL); + + if (!hv_result_success(status)) + hv_status_err(status, "pt:%lld vec:%d lapic-id:%lld\n", + partid, lapic_irq->lapic_vector, + lapic_irq->lapic_apic_id); +} + static int mshv_unmap_device_interrupt(union hv_device_id hv_devid, struct hv_interrupt_entry *irq_entry) { @@ -729,9 +800,12 @@ static void mshv_irqfd_update(struct mshv_partition *pt, struct mshv_irqfd *irqfd) { write_seqcount_begin(&irqfd->irqfd_irqe_sc); - irqfd->irqfd_girq_ent = mshv_ret_girq_entry(pt, - irqfd->irqfd_irqnum); + irqfd->irqfd_girq_ent = mshv_ret_girq_entry(pt, irqfd->irqfd_irqnum); mshv_copy_girq_info(&irqfd->irqfd_girq_ent, &irqfd->irqfd_lapic_irq); + +#if IS_ENABLED(CONFIG_X86_64) + mshv_do_guest_irq_retarget(pt->pt_id, irqfd); +#endif write_seqcount_end(&irqfd->irqfd_irqe_sc); } -- 2.51.2.vfs.0.1

